]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 12 Oct 2008 23:10:29 +0000 (16:10 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 12 Oct 2008 23:10:29 +0000 (16:10 -0700)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix kconfig typo and extra whitespace
  ext4: fix build failure without procfs
  ext4: add an option to control error handling on file data
  jbd2: don't dirty original metadata buffer on abort
  ext4: add checks for errors from jbd2
  jbd2: fix error handling for checkpoint io
  jbd2: abort when failed to log metadata buffers

393 files changed:
Documentation/kernel-parameters.txt
Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
Documentation/sparc/sbus_drivers.txt [deleted file]
MAINTAINERS
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/plat-omap/devices.c
arch/avr32/boards/atngw100/setup.c
arch/avr32/boards/atstk1000/atstk1002.c
arch/avr32/boards/atstk1000/atstk1003.c
arch/avr32/boards/atstk1000/atstk1004.c
arch/avr32/include/asm/atmel-mci.h
arch/avr32/include/asm/byteorder.h
arch/avr32/include/asm/io.h
arch/avr32/kernel/process.c
arch/avr32/kernel/setup.c
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mach-at32ap/clock.c
arch/avr32/mach-at32ap/clock.h
arch/avr32/mach-at32ap/include/mach/at32ap700x.h
arch/avr32/mach-at32ap/include/mach/board.h
arch/avr32/mach-at32ap/include/mach/io.h
arch/avr32/mach-at32ap/include/mach/portmux.h
arch/avr32/mach-at32ap/pdc.c
arch/avr32/mach-at32ap/pio.c
arch/avr32/oprofile/Makefile
arch/avr32/oprofile/backtrace.c [new file with mode: 0644]
arch/avr32/oprofile/op_model_avr32.c
arch/ia64/include/asm/siginfo.h
arch/powerpc/include/asm/siginfo.h
arch/sparc/Kconfig
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/asmmacro.h
arch/sparc/include/asm/bpp.h [deleted file]
arch/sparc/include/asm/bugs.h
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/dma-mapping_32.h
arch/sparc/include/asm/dma.h
arch/sparc/include/asm/dma_32.h [deleted file]
arch/sparc/include/asm/dma_64.h [deleted file]
arch/sparc/include/asm/ebus.h [deleted file]
arch/sparc/include/asm/ebus_32.h [deleted file]
arch/sparc/include/asm/ebus_64.h [deleted file]
arch/sparc/include/asm/ebus_dma.h [new file with mode: 0644]
arch/sparc/include/asm/elf_32.h
arch/sparc/include/asm/fhc.h
arch/sparc/include/asm/floppy_32.h
arch/sparc/include/asm/floppy_64.h
arch/sparc/include/asm/gpio.h [new file with mode: 0644]
arch/sparc/include/asm/io-unit.h
arch/sparc/include/asm/io_32.h
arch/sparc/include/asm/io_64.h
arch/sparc/include/asm/iommu_64.h
arch/sparc/include/asm/irq_64.h
arch/sparc/include/asm/mc146818rtc_64.h
arch/sparc/include/asm/memctrl.h [new file with mode: 0644]
arch/sparc/include/asm/mostek.h [deleted file]
arch/sparc/include/asm/mostek_32.h [deleted file]
arch/sparc/include/asm/mostek_64.h [deleted file]
arch/sparc/include/asm/obio.h
arch/sparc/include/asm/of_device.h
arch/sparc/include/asm/of_platform.h
arch/sparc/include/asm/oplib_32.h
arch/sparc/include/asm/page_32.h
arch/sparc/include/asm/page_64.h
arch/sparc/include/asm/parport.h
arch/sparc/include/asm/pci_32.h
arch/sparc/include/asm/pgtable_32.h
arch/sparc/include/asm/pgtable_64.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/ptrace_64.h
arch/sparc/include/asm/reboot.h [deleted file]
arch/sparc/include/asm/rtc.h [deleted file]
arch/sparc/include/asm/sbus.h [deleted file]
arch/sparc/include/asm/sbus_32.h [deleted file]
arch/sparc/include/asm/sbus_64.h [deleted file]
arch/sparc/include/asm/spinlock_32.h
arch/sparc/include/asm/spinlock_64.h
arch/sparc/include/asm/sstate.h [deleted file]
arch/sparc/include/asm/starfire.h
arch/sparc/include/asm/sun4paddr.h [deleted file]
arch/sparc/include/asm/sun4prom.h [deleted file]
arch/sparc/include/asm/system_32.h
arch/sparc/include/asm/system_64.h
arch/sparc/include/asm/thread_info_32.h
arch/sparc/include/asm/timer_32.h
arch/sparc/include/asm/vac-ops.h
arch/sparc/include/asm/vfc_ioctls.h [deleted file]
arch/sparc/include/asm/visasm.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/apc.c
arch/sparc/kernel/auxio.c
arch/sparc/kernel/devices.c
arch/sparc/kernel/dma.c [new file with mode: 0644]
arch/sparc/kernel/dma.h [new file with mode: 0644]
arch/sparc/kernel/ebus.c [deleted file]
arch/sparc/kernel/entry.S
arch/sparc/kernel/head.S
arch/sparc/kernel/idprom.c
arch/sparc/kernel/ioport.c
arch/sparc/kernel/irq.h
arch/sparc/kernel/of_device.c
arch/sparc/kernel/pcic.c
arch/sparc/kernel/pmc.c
arch/sparc/kernel/process.c
arch/sparc/kernel/prom.c
arch/sparc/kernel/setup.c
arch/sparc/kernel/sparc_ksyms.c
arch/sparc/kernel/sun4c_irq.c
arch/sparc/kernel/sun4d_irq.c
arch/sparc/kernel/sun4d_smp.c
arch/sparc/kernel/sun4m_irq.c
arch/sparc/kernel/sun4m_smp.c
arch/sparc/kernel/sun4setup.c [deleted file]
arch/sparc/kernel/sys_sparc.c
arch/sparc/kernel/tick14.c
arch/sparc/kernel/time.c
arch/sparc/kernel/traps.c
arch/sparc/mm/Makefile
arch/sparc/mm/btfixup.c
arch/sparc/mm/fault.c
arch/sparc/mm/init.c
arch/sparc/mm/io-unit.c
arch/sparc/mm/iommu.c
arch/sparc/mm/nosrmmu.c [deleted file]
arch/sparc/mm/srmmu.c
arch/sparc/mm/sun4c.c
arch/sparc/prom/Makefile
arch/sparc/prom/bootstr.c
arch/sparc/prom/console.c
arch/sparc/prom/init.c
arch/sparc/prom/memory.c
arch/sparc/prom/ranges.c
arch/sparc/prom/sun4prom.c [deleted file]
arch/sparc64/Kconfig
arch/sparc64/Makefile
arch/sparc64/kernel/Makefile
arch/sparc64/kernel/auxio.c
arch/sparc64/kernel/central.c
arch/sparc64/kernel/chmc.c
arch/sparc64/kernel/cpu.c
arch/sparc64/kernel/ds.c
arch/sparc64/kernel/ebus.c
arch/sparc64/kernel/entry.h
arch/sparc64/kernel/head.S
arch/sparc64/kernel/hvapi.c
arch/sparc64/kernel/hvcalls.S
arch/sparc64/kernel/irq.c
arch/sparc64/kernel/of_device.c
arch/sparc64/kernel/pci.c
arch/sparc64/kernel/pci_common.c
arch/sparc64/kernel/pci_fire.c
arch/sparc64/kernel/pci_impl.h
arch/sparc64/kernel/pci_msi.c
arch/sparc64/kernel/pci_psycho.c
arch/sparc64/kernel/pci_sabre.c
arch/sparc64/kernel/pci_schizo.c
arch/sparc64/kernel/pci_sun4v.c
arch/sparc64/kernel/pci_sun4v_asm.S
arch/sparc64/kernel/power.c
arch/sparc64/kernel/process.c
arch/sparc64/kernel/prom.c
arch/sparc64/kernel/psycho_common.c [new file with mode: 0644]
arch/sparc64/kernel/psycho_common.h [new file with mode: 0644]
arch/sparc64/kernel/ptrace.c
arch/sparc64/kernel/reboot.c [new file with mode: 0644]
arch/sparc64/kernel/sbus.c
arch/sparc64/kernel/sparc64_ksyms.c
arch/sparc64/kernel/sstate.c
arch/sparc64/kernel/starfire.c
arch/sparc64/kernel/sys_sparc32.c
arch/sparc64/kernel/syscalls.S
arch/sparc64/kernel/systbls.S
arch/sparc64/kernel/time.c
arch/sparc64/kernel/traps.c
arch/sparc64/kernel/vio.c
arch/sparc64/kernel/visemul.c
arch/sparc64/mm/fault.c
arch/sparc64/mm/init.c
arch/sparc64/mm/init.h [new file with mode: 0644]
arch/sparc64/mm/tlb.c
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/Kconfig.debug
arch/x86/Makefile_32.cpu
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/edd.c
arch/x86/boot/video-vesa.c
arch/x86/configs/i386_defconfig
arch/x86/configs/x86_64_defconfig
arch/x86/ia32/ia32_signal.c
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/doublefault_32.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/i387.c
arch/x86/kernel/io_apic_64.c
arch/x86/kernel/ldt.c
arch/x86/kernel/microcode.c [deleted file]
arch/x86/kernel/microcode_amd.c [new file with mode: 0644]
arch/x86/kernel/microcode_core.c [new file with mode: 0644]
arch/x86/kernel/microcode_intel.c [new file with mode: 0644]
arch/x86/kernel/paravirt-spinlocks.c [new file with mode: 0644]
arch/x86/kernel/paravirt.c
arch/x86/kernel/process_32.c
arch/x86/kernel/process_64.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/setup.c
arch/x86/kernel/signal_32.c
arch/x86/kernel/signal_64.c
arch/x86/kernel/smp.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/tlb_32.c
arch/x86/kernel/traps_32.c
arch/x86/kernel/traps_64.c
arch/x86/kernel/vmlinux_64.lds.S
arch/x86/kernel/xsave.c
arch/x86/mm/fault.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/xen/Kconfig
arch/x86/xen/Makefile
arch/x86/xen/debugfs.c [new file with mode: 0644]
arch/x86/xen/debugfs.h [new file with mode: 0644]
arch/x86/xen/enlighten.c
arch/x86/xen/irq.c [new file with mode: 0644]
arch/x86/xen/mmu.c
arch/x86/xen/mmu.h
arch/x86/xen/multicalls.c
arch/x86/xen/smp.c
arch/x86/xen/spinlock.c [new file with mode: 0644]
arch/x86/xen/time.c
arch/x86/xen/xen-asm_32.S
arch/x86/xen/xen-asm_64.S
arch/x86/xen/xen-ops.h
drivers/acpi/glue.c
drivers/ata/Kconfig
drivers/atm/fore200e.c
drivers/atm/fore200e.h
drivers/block/sunvdc.c
drivers/block/xen-blkfront.c
drivers/char/hvc_xen.c
drivers/char/hw_random/n2-drv.c
drivers/char/rtc.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/ultra45_env.c [new file with mode: 0644]
drivers/input/misc/sparcspkr.c
drivers/input/serio/i8042-sparcio.h
drivers/input/xen-kbdfront.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-sunfire.c [new file with mode: 0644]
drivers/mmc/Kconfig
drivers/mmc/card/Kconfig
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/host/Kconfig
drivers/mmc/host/atmel-mci-regs.h
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/maps/sun_uflash.c
drivers/net/e1000/e1000_main.c
drivers/net/myri_sbus.c
drivers/net/myri_sbus.h
drivers/net/niu.c
drivers/net/smc911x.c
drivers/net/sunbmac.c
drivers/net/sunbmac.h
drivers/net/sunhme.c
drivers/net/sunhme.h
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/sunqe.h
drivers/net/sunvnet.c
drivers/net/xen-netfront.c
drivers/parport/parport_sunbpp.c
drivers/power/Kconfig
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-bq4802.c [new file with mode: 0644]
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-starfire.c [new file with mode: 0644]
drivers/rtc/rtc-sun4v.c [new file with mode: 0644]
drivers/sbus/Makefile
drivers/sbus/char/Kconfig
drivers/sbus/char/Makefile
drivers/sbus/char/bbc_envctrl.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/bbc_i2c.h
drivers/sbus/char/bpp.c [deleted file]
drivers/sbus/char/cpwatchdog.c [deleted file]
drivers/sbus/char/display7seg.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/rtc.c [deleted file]
drivers/sbus/char/uctrl.c
drivers/sbus/char/vfc.h [deleted file]
drivers/sbus/char/vfc_dev.c [deleted file]
drivers/sbus/char/vfc_i2c.c [deleted file]
drivers/sbus/char/vfc_i2c.h [deleted file]
drivers/sbus/dvma.c [deleted file]
drivers/sbus/sbus.c [deleted file]
drivers/scsi/esp_scsi.h
drivers/scsi/qlogicpti.c
drivers/scsi/qlogicpti.h
drivers/scsi/sun_esp.c
drivers/serial/sunhv.c
drivers/serial/sunsab.c
drivers/serial/sunsu.c
drivers/serial/sunzilog.c
drivers/usb/host/ehci.h
drivers/video/Kconfig
drivers/video/bw2.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/console/Kconfig
drivers/video/ffb.c
drivers/video/leo.c
drivers/video/p9100.c
drivers/video/tcx.c
drivers/video/xen-fbfront.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/at91sam9_wdt.c [new file with mode: 0644]
drivers/watchdog/cpwd.c [new file with mode: 0644]
drivers/watchdog/it87_wdt.c [new file with mode: 0644]
drivers/watchdog/omap_wdt.c
drivers/watchdog/omap_wdt.h
drivers/watchdog/orion5x_wdt.c [new file with mode: 0644]
drivers/watchdog/riowd.c [moved from drivers/sbus/char/riowatchdog.c with 51% similarity]
drivers/watchdog/w83697ug_wdt.c [new file with mode: 0644]
drivers/xen/Makefile
drivers/xen/balloon.c
drivers/xen/cpu_hotplug.c [new file with mode: 0644]
drivers/xen/events.c
drivers/xen/grant-table.c
drivers/xen/xenbus/xenbus_probe.c
fs/cifs/misc.c
fs/ioctl.c
include/asm-generic/siginfo.h
include/asm-parisc/siginfo.h
include/asm-x86/bios_ebda.h
include/asm-x86/boot.h
include/asm-x86/desc.h
include/asm-x86/microcode.h [new file with mode: 0644]
include/asm-x86/mmzone_64.h
include/asm-x86/page_32.h
include/asm-x86/paravirt.h
include/asm-x86/processor.h
include/asm-x86/ptrace.h
include/asm-x86/smp.h
include/asm-x86/spinlock.h
include/asm-x86/tlbflush.h
include/asm-x86/traps.h
include/asm-x86/xen/hypervisor.h
include/linux/elf.h
include/linux/kernel.h
include/linux/key.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/host.h
include/linux/mmdebug.h [new file with mode: 0644]
include/linux/rtc/m48t59.h
include/linux/sched.h
include/linux/usb/ehci_def.h [new file with mode: 0644]
include/sound/core.h
include/sound/memalloc.h
include/xen/balloon.h [deleted file]
include/xen/events.h
kernel/sysctl.c
lib/Kconfig.debug
lib/cmdline.c
mm/vmalloc.c
net/ipv4/ip_gre.c
net/netfilter/ipvs/Kconfig
scripts/Kbuild.include
sound/core/memalloc.c
sound/sparc/amd7930.c
sound/sparc/cs4231.c
sound/sparc/dbri.c

index 25efbaf1f59bc23ef21cdd3d50731509e06fbeef..2443f5bb43648e5a2c50bc94d33703f88360880a 100644 (file)
@@ -658,11 +658,12 @@ and is between 256 and 4096 characters. It is defined in the file
        earlyprintk=    [X86-32,X86-64,SH,BLACKFIN]
                        earlyprintk=vga
                        earlyprintk=serial[,ttySn[,baudrate]]
+                       earlyprintk=dbgp
 
                        Append ",keep" to not disable it when the real console
                        takes over.
 
-                       Only vga or serial at a time, not both.
+                       Only vga or serial or usb debug port at a time.
 
                        Currently only ttyS0 and ttyS1 are supported.
 
@@ -1231,6 +1232,29 @@ and is between 256 and 4096 characters. It is defined in the file
                                 or
                                 memmap=0x10000$0x18690000
 
+       memory_corruption_check=0/1 [X86]
+                       Some BIOSes seem to corrupt the first 64k of
+                       memory when doing things like suspend/resume.
+                       Setting this option will scan the memory
+                       looking for corruption.  Enabling this will
+                       both detect corruption and prevent the kernel
+                       from using the memory being corrupted.
+                       However, its intended as a diagnostic tool; if
+                       repeatable BIOS-originated corruption always
+                       affects the same memory, you can use memmap=
+                       to prevent the kernel from using that memory.
+
+       memory_corruption_check_size=size [X86]
+                       By default it checks for corruption in the low
+                       64k, making this memory unavailable for normal
+                       use.  Use this parameter to scan for
+                       corruption in more or less memory.
+
+       memory_corruption_check_period=seconds [X86]
+                       By default it checks for corruption every 60
+                       seconds.  Use this parameter to check at some
+                       other rate.  0 disables periodic checking.
+
        memtest=        [KNL,X86] Enable memtest
                        Format: <integer>
                        range: 0,4 : pattern number
index b54cb5048dfa8c1f23176382cf31d2f1b409e15b..87a7c07ab6581ecd6a96d354ac5920e633548ea8 100644 (file)
@@ -5073,8 +5073,7 @@ struct _snd_pcm_runtime {
       with <constant>SNDRV_DMA_TYPE_CONTINUOUS</constant> type and the
       <function>snd_dma_continuous_data(GFP_KERNEL)</function> device pointer,
       where <constant>GFP_KERNEL</constant> is the kernel allocation flag to
-      use.  For the SBUS, <constant>SNDRV_DMA_TYPE_SBUS</constant> and
-      <function>snd_dma_sbus_data(sbus_dev)</function> are used instead.
+      use.
       For the PCI scatter-gather buffers, use
       <constant>SNDRV_DMA_TYPE_DEV_SG</constant> with
       <function>snd_dma_pci_data(pci)</function>
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
deleted file mode 100644 (file)
index eb1e28a..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-
-               Writing SBUS Drivers
-
-           David S. Miller (davem@redhat.com)
-
-       The SBUS driver interfaces of the Linux kernel have been
-revamped completely for 2.4.x for several reasons.  Foremost were
-performance and complexity concerns.  This document details these
-new interfaces and how they are used to write an SBUS device driver.
-
-       SBUS drivers need to include <asm/sbus.h> to get access
-to functions and structures described here.
-
-               Probing and Detection
-
-       Each SBUS device inside the machine is described by a
-structure called "struct sbus_dev".  Likewise, each SBUS bus
-found in the system is described by a "struct sbus_bus".  For
-each SBUS bus, the devices underneath are hung in a tree-like
-fashion off of the bus structure.
-
-       The SBUS device structure contains enough information
-for you to implement your device probing algorithm and obtain
-the bits necessary to run your device.  The most commonly
-used members of this structure, and their typical usage,
-will be detailed below.
-
-       Here is a piece of skeleton code for performing a device
-probe in an SBUS driver under Linux:
-
-       static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
-       {
-               struct mysdevice *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-
-               if (!mp)
-                       return -ENODEV;
-
-               ...
-               dev_set_drvdata(&sdev->ofdev.dev, mp);
-               return 0;
-               ...
-       }
-
-       static int __devinit mydevice_probe(struct of_device *dev,
-                                           const struct of_device_id *match)
-       {
-               struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-               return mydevice_probe_one(sdev);
-       }
-
-       static int __devexit mydevice_remove(struct of_device *dev)
-       {
-               struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-               struct mydevice *mp = dev_get_drvdata(&dev->dev);
-
-               return mydevice_remove_one(sdev, mp);
-       }
-
-       static struct of_device_id mydevice_match[] = {
-               {
-                       .name = "mydevice",
-               },
-               {},
-       };
-
-       MODULE_DEVICE_TABLE(of, mydevice_match);
-
-       static struct of_platform_driver mydevice_driver = {
-               .match_table    = mydevice_match,
-               .probe          = mydevice_probe,
-               .remove         = __devexit_p(mydevice_remove),
-               .driver         = {
-                       .name           = "mydevice",
-               },
-       };
-
-       static int __init mydevice_init(void)
-       {
-               return of_register_driver(&mydevice_driver, &sbus_bus_type);
-       }
-
-       static void __exit mydevice_exit(void)
-       {
-               of_unregister_driver(&mydevice_driver);
-       }
-
-       module_init(mydevice_init);
-       module_exit(mydevice_exit);
-
-       The mydevice_match table is a series of entries which
-describes what SBUS devices your driver is meant for.  In the
-simplest case you specify a string for the 'name' field.  Every
-SBUS device with a 'name' property matching your string will
-be passed one-by-one to your .probe method.
-
-       You should store away your device private state structure
-pointer in the drvdata area so that you can retrieve it later on
-in your .remove method.
-
-       Any memory allocated, registers mapped, IRQs registered,
-etc. must be undone by your .remove method so that all resources
-of your device are released by the time it returns.
-
-       You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
-and for_all_sbusdev() interfaces.  They are deprecated, will be
-removed, and no new driver should reference them ever.
-
-               Mapping and Accessing I/O Registers
-
-       Each SBUS device structure contains an array of descriptors
-which describe each register set. We abuse struct resource for that.
-They each correspond to the "reg" properties provided by the OBP firmware.
-
-       Before you can access your device's registers you must map
-them.  And later if you wish to shutdown your driver (for module
-unload or similar) you must unmap them.  You must treat them as
-a resource, which you allocate (map) before using and free up
-(unmap) when you are done with it.
-
-       The mapping information is stored in an opaque value
-typed as an "unsigned long".  This is the type of the return value
-of the mapping interface, and the arguments to the unmapping
-interface.  Let's say you want to map the first set of registers.
-Perhaps part of your driver software state structure looks like:
-
-       struct mydevice {
-               unsigned long control_regs;
-          ...
-               struct sbus_dev *sdev;
-          ...
-       };
-
-       At initialization time you then use the sbus_ioremap
-interface to map in your registers, like so:
-
-       static void init_one_mydevice(struct sbus_dev *sdev)
-       {
-               struct mydevice *mp;
-               ...
-
-               mp->control_regs = sbus_ioremap(&sdev->resource[0], 0,
-                                       CONTROL_REGS_SIZE, "mydevice regs");
-               if (!mp->control_regs) {
-                       /* Failure, cleanup and return. */
-               }
-       }
-
-       Second argument to sbus_ioremap is an offset for
-cranky devices with broken OBP PROM. The sbus_ioremap uses only
-a start address and flags from the resource structure.
-Therefore it is possible to use the same resource to map
-several sets of registers or even to fabricate a resource
-structure if driver gets physical address from some private place.
-This practice is discouraged though. Use whatever OBP PROM
-provided to you.
-
-       And here is how you might unmap these registers later at
-driver shutdown or module unload time, using the sbus_iounmap
-interface:
-
-       static void mydevice_unmap_regs(struct mydevice *mp)
-       {
-               sbus_iounmap(mp->control_regs, CONTROL_REGS_SIZE);
-       }
-
-       Finally, to actually access your registers there are 6
-interface routines at your disposal.  Accesses are byte (8 bit),
-word (16 bit), or longword (32 bit) sized.  Here they are:
-
-       u8 sbus_readb(unsigned long reg)                /* read byte */
-       u16 sbus_readw(unsigned long reg)               /* read word */
-       u32 sbus_readl(unsigned long reg)               /* read longword */
-       void sbus_writeb(u8 value, unsigned long reg)   /* write byte */
-       void sbus_writew(u16 value, unsigned long reg)  /* write word */
-       void sbus_writel(u32 value, unsigned long reg)  /* write longword */
-
-       So, let's say your device has a control register of some sort
-at offset zero.  The following might implement resetting your device:
-
-       #define CONTROL         0x00UL
-
-       #define CONTROL_RESET   0x00000001      /* Reset hardware */
-
-       static void mydevice_reset(struct mydevice *mp)
-       {
-               sbus_writel(CONTROL_RESET, mp->regs + CONTROL);
-       }
-
-       Or perhaps there is a data port register at an offset of
-16 bytes which allows you to read bytes from a fifo in the device:
-
-       #define DATA            0x10UL
-
-       static u8 mydevice_get_byte(struct mydevice *mp)
-       {
-               return sbus_readb(mp->regs + DATA);
-       }
-
-       It's pretty straightforward, and clueful readers may have
-noticed that these interfaces mimick the PCI interfaces of the
-Linux kernel.  This was not by accident.
-
-       WARNING:
-
-               DO NOT try to treat these opaque register mapping
-               values as a memory mapped pointer to some structure
-               which you can dereference.
-
-               It may be memory mapped, it may not be.  In fact it
-               could be a physical address, or it could be the time
-               of day xor'd with 0xdeadbeef.  :-)
-
-               Whatever it is, it's an implementation detail.  The
-               interface was done this way to shield the driver
-               author from such complexities.
-
-                       Doing DVMA
-
-       SBUS devices can perform DMA transactions in a way similar
-to PCI but dissimilar to ISA, e.g. DMA masters supply address.
-In contrast to PCI, however, that address (a bus address) is
-translated by IOMMU before a memory access is performed and therefore
-it is virtual. Sun calls this procedure DVMA.
-
-       Linux supports two styles of using SBUS DVMA: "consistent memory"
-and "streaming DVMA". CPU view of consistent memory chunk is, well,
-consistent with a view of a device. Think of it as an uncached memory.
-Typically this way of doing DVMA is not very fast and drivers use it
-mostly for control blocks or queues. On some CPUs we cannot flush or
-invalidate individual pages or cache lines and doing explicit flushing
-over ever little byte in every control block would be wasteful.
-
-Streaming DVMA is a preferred way to transfer large amounts of data.
-This process works in the following way:
-1. a CPU stops accessing a certain part of memory,
-   flushes its caches covering that memory;
-2. a device does DVMA accesses, then posts an interrupt;
-3. CPU invalidates its caches and starts to access the memory.
-
-A single streaming DVMA operation can touch several discontiguous
-regions of a virtual bus address space. This is called a scatter-gather
-DVMA.
-
-[TBD: Why do not we neither Solaris attempt to map disjoint pages
-into a single virtual chunk with the help of IOMMU, so that non SG
-DVMA masters would do SG? It'd be very helpful for RAID.]
-
-       In order to perform a consistent DVMA a driver does something
-like the following:
-
-       char *mem;              /* Address in the CPU space */
-       u32 busa;               /* Address in the SBus space */
-
-       mem = (char *) sbus_alloc_consistent(sdev, MYMEMSIZE, &busa);
-
-       Then mem is used when CPU accesses this memory and u32
-is fed to the device so that it can do DVMA. This is typically
-done with an sbus_writel() into some device register.
-
-       Do not forget to free the DVMA resources once you are done:
-
-       sbus_free_consistent(sdev, MYMEMSIZE, mem, busa);
-
-       Streaming DVMA is more interesting. First you allocate some
-memory suitable for it or pin down some user pages. Then it all works
-like this:
-
-       char *mem = argumen1;
-       unsigned int size = argument2;
-       u32 busa;               /* Address in the SBus space */
-
-       *mem = 1;               /* CPU can access */
-       busa = sbus_map_single(sdev, mem, size);
-       if (busa == 0) .......
-
-       /* Tell the device to use busa here */
-       /* CPU cannot access the memory without sbus_dma_sync_single() */
-
-       sbus_unmap_single(sdev, busa, size);
-       if (*mem == 0) ....     /* CPU can access again */
-
-       It is possible to retain mappings and ask the device to
-access data again and again without calling sbus_unmap_single.
-However, CPU caches must be invalidated with sbus_dma_sync_single
-before such access.
-
-[TBD but what about writeback caches here... do we have any?]
-
-       There is an equivalent set of functions doing the same thing
-only with several memory segments at once for devices capable of
-scatter-gather transfers. Use the Source, Luke.
-
-                       Examples
-
-       drivers/net/sunhme.c
-       This is a complicated driver which illustrates many concepts
-discussed above and plus it handles both PCI and SBUS boards.
-
-       drivers/scsi/esp.c
-       Check it out for scatter-gather DVMA.
-
-       drivers/sbus/char/bpp.c
-       A non-DVMA device.
-
-       drivers/net/sunlance.c
-       Lance driver abuses consistent mappings for data transfer.
-It is a nifty trick which we do not particularly recommend...
-Just check it out and know that it's legal.
index 587f418ed00d46eceb92cf6251e3c49d1d87c029..8bf72d378332a19f834c9707935c5015d16822c1 100644 (file)
@@ -390,6 +390,11 @@ L: iommu@lists.linux-foundation.org
 T:     git://git.kernel.org/pub/scm/linux/kernel/git/joro/linux-2.6-iommu.git
 S:     Supported
 
+AMD MICROCODE UPDATE SUPPORT
+P:      Peter Oruba
+M:      peter.oruba@amd.com
+S:      Supported
+
 AMS (Apple Motion Sensor) DRIVER
 P:     Stelian Pop
 M:     stelian@popies.net
index e67c843baa022dd375ad57320c766b13bd15a0a8..9f5ce1ce5840845d2a6f42d2306ed0f75689d717 100644 (file)
 #define CPU_CONF               ORION5X_BRIDGE_REG(0x100)
 #define CPU_CTRL               ORION5X_BRIDGE_REG(0x104)
 #define CPU_RESET_MASK         ORION5X_BRIDGE_REG(0x108)
+#define  WDT_RESET             0x0002
 #define CPU_SOFT_RESET         ORION5X_BRIDGE_REG(0x10c)
 #define POWER_MNG_CTRL_REG     ORION5X_BRIDGE_REG(0x11C)
 #define BRIDGE_CAUSE           ORION5X_BRIDGE_REG(0x110)
+#define  WDT_INT_REQ           0x0008
 #define BRIDGE_MASK            ORION5X_BRIDGE_REG(0x114)
 #define  BRIDGE_INT_TIMER0     0x0002
 #define  BRIDGE_INT_TIMER1     0x0004
index a716ecd1db2792ddc5760a039ccaa83f799c011e..97187fa0ae52b529a1f51453a29d2f2577c0605a 100644 (file)
@@ -441,16 +441,8 @@ static inline void omap_init_uwire(void) {}
 
 #if    defined(CONFIG_OMAP_WATCHDOG) || defined(CONFIG_OMAP_WATCHDOG_MODULE)
 
-#ifdef CONFIG_ARCH_OMAP24XX
-#define        OMAP_WDT_BASE           0x48022000
-#else
-#define        OMAP_WDT_BASE           0xfffeb000
-#endif
-
 static struct resource wdt_resources[] = {
        {
-               .start          = OMAP_WDT_BASE,
-               .end            = OMAP_WDT_BASE + 0x4f,
                .flags          = IORESOURCE_MEM,
        },
 };
@@ -464,6 +456,19 @@ static struct platform_device omap_wdt_device = {
 
 static void omap_init_wdt(void)
 {
+       if (cpu_is_omap16xx())
+               wdt_resources[0].start = 0xfffeb000;
+       else if (cpu_is_omap2420())
+               wdt_resources[0].start = 0x48022000; /* WDT2 */
+       else if (cpu_is_omap2430())
+               wdt_resources[0].start = 0x49016000; /* WDT2 */
+       else if (cpu_is_omap343x())
+               wdt_resources[0].start = 0x48314000; /* WDT2 */
+       else
+               return;
+
+       wdt_resources[0].end = wdt_resources[0].start + 0x4f;
+
        (void) platform_device_register(&omap_wdt_device);
 }
 #else
index b8286f1ce854ada7c5cf4750732da32c0305a46a..6c54580a66df77bdcba2d1e889c95ba9b6524291 100644 (file)
@@ -9,6 +9,7 @@
  */
 #include <linux/clk.h>
 #include <linux/etherdevice.h>
+#include <linux/gpio.h>
 #include <linux/irq.h>
 #include <linux/i2c.h>
 #include <linux/i2c-gpio.h>
@@ -53,8 +54,11 @@ static struct spi_board_info spi0_board_info[] __initdata = {
 };
 
 static struct mci_platform_data __initdata mci0_data = {
-       .detect_pin     = GPIO_PIN_PC(25),
-       .wp_pin         = GPIO_PIN_PE(0),
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = GPIO_PIN_PC(25),
+               .wp_pin         = GPIO_PIN_PE(0),
+       },
 };
 
 /*
@@ -190,7 +194,7 @@ static int __init atngw100_init(void)
         * PB28/EXTINT3 doesn't; it should be SMBALERT# (for PMBus),
         * but it's not available off-board.
         */
-       at32_select_periph(GPIO_PIN_PB(28), 0, AT32_GPIOF_PULLUP);
+       at32_select_periph(GPIO_PIOB_BASE, 1 << 28, 0, AT32_GPIOF_PULLUP);
        at32_select_gpio(i2c_gpio_data.sda_pin,
                AT32_GPIOF_MULTIDRV | AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
        at32_select_gpio(i2c_gpio_data.scl_pin,
@@ -204,6 +208,15 @@ postcore_initcall(atngw100_init);
 
 static int __init atngw100_arch_init(void)
 {
+       /* PB30 is the otherwise unused jumper on the mainboard, with an
+        * external pullup; the jumper grounds it.  Use it however you
+        * like, including letting U-Boot or Linux tweak boot sequences.
+        */
+       at32_select_gpio(GPIO_PIN_PB(30), 0);
+       gpio_request(GPIO_PIN_PB(30), "j15");
+       gpio_direction_input(GPIO_PIN_PB(30));
+       gpio_export(GPIO_PIN_PB(30), false);
+
        /* set_irq_type() after the arch_initcall for EIC has run, and
         * before the I2C subsystem could try using this IRQ.
         */
index dfc3443e23aa3df4cb0033c579a5f7a3d4679623..29e5b51a7fd2b8801a23655e17edcff41ade6ab2 100644 (file)
@@ -232,7 +232,7 @@ static void __init atstk1002_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -264,16 +264,20 @@ void __init setup_board(void)
 
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
 
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+
 /* MMC card detect requires MACB0 *NOT* be used */
 #ifdef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
-static struct mci_platform_data __initdata mci0_data = {
-       .detect_pin     = GPIO_PIN_PC(14),      /* gpio30/sdcd */
-       .wp_pin         = GPIO_PIN_PC(15),      /* gpio31/sdwp */
-};
-#define MCI_PDATA      &mci0_data
+               .detect_pin     = GPIO_PIN_PC(14), /* gpio30/sdcd */
+               .wp_pin         = GPIO_PIN_PC(15), /* gpio31/sdwp */
 #else
-#define MCI_PDATA      NULL
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
 #endif /* SW6 for sd{cd,wp} routing */
+       },
+};
 
 #endif /* SW2 for MMC signal routing */
 
@@ -326,13 +330,14 @@ static int __init atstk1002_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, MCI_PDATA);
+       at32_add_device_mci(0, &mci0_data);
 #endif
 #ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
        set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
 #else
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size, 0);
+                            fbmem_start, fbmem_size,
+                            ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index 0cf664174c1766f129366aecce8a6321aeb77ce8..be089d7f37ebf1b0fe955475417fce4fb66e86f9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/spi/spi.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -66,6 +67,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
+       },
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1003_setup_extdac(void)
 {
@@ -84,7 +95,7 @@ static void __init atstk1003_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -154,7 +165,7 @@ static int __init atstk1003_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, NULL);
+       at32_add_device_mci(0, &mci0_data);
 #endif
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
index 50a5273e5916ddc285d5be2e3604a3b3df6c76d7..248ef237c167b95283c30dec20ca0080c97e6feb 100644 (file)
@@ -21,6 +21,7 @@
 #include <video/atmel_lcdc.h>
 
 #include <asm/setup.h>
+#include <asm/atmel-mci.h>
 
 #include <mach/at32ap700x.h>
 #include <mach/board.h>
@@ -71,6 +72,16 @@ static struct spi_board_info spi1_board_info[] __initdata = { {
 } };
 #endif
 
+#ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -ENODEV,
+               .wp_pin         = -ENODEV,
+       },
+};
+#endif
+
 #ifdef CONFIG_BOARD_ATSTK1000_EXTDAC
 static void __init atstk1004_setup_extdac(void)
 {
@@ -89,7 +100,7 @@ static void __init atstk1004_setup_extdac(void)
                goto err_set_clk;
        }
 
-       at32_select_periph(GPIO_PIN_PA(30), GPIO_PERIPH_A, 0);
+       at32_select_periph(GPIO_PIOA_BASE, (1 << 30), GPIO_PERIPH_A, 0);
        at73c213_data.dac_clk = gclk;
 
 err_set_clk:
@@ -137,10 +148,11 @@ static int __init atstk1004_init(void)
        at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
 #endif
 #ifndef CONFIG_BOARD_ATSTK100X_SW2_CUSTOM
-       at32_add_device_mci(0, NULL);
+       at32_add_device_mci(0, &mci0_data);
 #endif
        at32_add_device_lcdc(0, &atstk1000_lcdc_data,
-                            fbmem_start, fbmem_size, 0);
+                            fbmem_start, fbmem_size,
+                            ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL);
        at32_add_device_usba(0, NULL);
 #ifndef CONFIG_BOARD_ATSTK100X_SW3_CUSTOM
        at32_add_device_ssc(0, ATMEL_SSC_TX);
index c2ea6e1c9aa1a842cb7de5eaba568246d0706a20..59f3fadd0b68a45e07353fb8d6e3d97d5e7aba90 100644 (file)
@@ -1,9 +1,39 @@
 #ifndef __ASM_AVR32_ATMEL_MCI_H
 #define __ASM_AVR32_ATMEL_MCI_H
 
-struct mci_platform_data {
+#define ATMEL_MCI_MAX_NR_SLOTS 2
+
+struct dma_slave;
+
+/**
+ * struct mci_slot_pdata - board-specific per-slot configuration
+ * @bus_width: Number of data lines wired up the slot
+ * @detect_pin: GPIO pin wired to the card detect switch
+ * @wp_pin: GPIO pin wired to the write protect sensor
+ *
+ * If a given slot is not present on the board, @bus_width should be
+ * set to 0. The other fields are ignored in this case.
+ *
+ * Any pins that aren't available should be set to a negative value.
+ *
+ * Note that support for multiple slots is experimental -- some cards
+ * might get upset if we don't get the clock management exactly right.
+ * But in most cases, it should work just fine.
+ */
+struct mci_slot_pdata {
+       unsigned int            bus_width;
        int                     detect_pin;
        int                     wp_pin;
 };
 
+/**
+ * struct mci_platform_data - board-specific MMC/SDcard configuration
+ * @dma_slave: DMA slave interface to use in data transfers, or NULL.
+ * @slot: Per-slot configuration data.
+ */
+struct mci_platform_data {
+       struct dma_slave        *dma_slave;
+       struct mci_slot_pdata   slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
 #endif /* __ASM_AVR32_ATMEL_MCI_H */
index d77b48ba73387ba57ac932e5a6676d43b1c6a584..8e3af02076dd59d8eedcf2cec413392ee867f68d 100644 (file)
@@ -7,6 +7,9 @@
 #include <asm/types.h>
 #include <linux/compiler.h>
 
+#define __BIG_ENDIAN
+#define __SWAB_64_THRU_32__
+
 #ifdef __CHECKER__
 extern unsigned long __builtin_bswap_32(unsigned long x);
 extern unsigned short __builtin_bswap_16(unsigned short x);
@@ -17,15 +20,18 @@ extern unsigned short __builtin_bswap_16(unsigned short x);
  * the result.
  */
 #if !(__GNUC__ == 4 && __GNUC_MINOR__ < 2)
-#define __arch__swab32(x) __builtin_bswap_32(x)
-#define __arch__swab16(x) __builtin_bswap_16(x)
-#endif
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+       return __builtin_bswap_16(val);
+}
+#define __arch_swab16 __arch_swab16
 
-#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
-# define __BYTEORDER_HAS_U64__
-# define __SWAB_64_THRU_32__
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+       return __builtin_bswap_32(val);
+}
+#define __arch_swab32 __arch_swab32
 #endif
 
-#include <linux/byteorder/big_endian.h>
-
+#include <linux/byteorder.h>
 #endif /* __ASM_AVR32_BYTEORDER_H */
index a520f77ead96e62d02ee2197d85c2a76fa46c9e2..22c97ef92201bff82b5a7bc7a6fe139147c014a4 100644 (file)
@@ -160,6 +160,14 @@ BUILDIO_IOPORT(l, u32)
 #define readw_relaxed                  readw
 #define readl_relaxed                  readl
 
+#define readb_be                       __raw_readb
+#define readw_be                       __raw_readw
+#define readl_be                       __raw_readl
+
+#define writeb_be                      __raw_writeb
+#define writew_be                      __raw_writew
+#define writel_be                      __raw_writel
+
 #define __BUILD_MEMORY_STRING(bwl, type)                               \
 static inline void writes##bwl(volatile void __iomem *addr,            \
                               const void *data, unsigned int count)    \
index 2c08ac992ac3d8435c2284224cbbd5a0691ac085..134d5302b6dd21fda7f676a9bdfa3923b19e5998 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/fs.h>
+#include <linux/pm.h>
 #include <linux/ptrace.h>
 #include <linux/reboot.h>
 #include <linux/tick.h>
@@ -20,7 +21,7 @@
 
 #include <mach/pm.h>
 
-void (*pm_power_off)(void) = NULL;
+void (*pm_power_off)(void);
 EXPORT_SYMBOL(pm_power_off);
 
 /*
index d8e623c426c1f324c37369eca13cf358e3b85ab1..5c7083916c33c14792728da5a08295476daebc17 100644 (file)
@@ -283,6 +283,25 @@ static int __init early_parse_fbmem(char *p)
 }
 early_param("fbmem", early_parse_fbmem);
 
+/*
+ * Pick out the memory size.  We look for mem=size@start,
+ * where start and size are "size[KkMmGg]"
+ */
+static int __init early_mem(char *p)
+{
+       resource_size_t size, start;
+
+       start = system_ram->start;
+       size  = memparse(p, &p);
+       if (*p == '@')
+               start = memparse(p + 1, &p);
+
+       system_ram->start = start;
+       system_ram->end = system_ram->start + size - 1;
+       return 0;
+}
+early_param("mem", early_mem);
+
 static int __init parse_tag_core(struct tag *tag)
 {
        if (tag->hdr.size > 2) {
index e01dbe4ebb404fdeda8dd29b38d666908ff426bc..813b6844cdf67a1ec485ccc4f3839baa42c2682d 100644 (file)
@@ -82,8 +82,9 @@ static struct platform_device _name##_id##_device = {         \
        .num_resources  = ARRAY_SIZE(_name##_id##_resource),    \
 }
 
-#define select_peripheral(pin, periph, flags)                  \
-       at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
+#define select_peripheral(port, pin_mask, periph, flags)       \
+       at32_select_periph(GPIO_##port##_BASE, pin_mask,        \
+                          GPIO_##periph, flags)
 
 #define DEV_CLK(_name, devname, bus, _index)                   \
 static struct clk devname##_##_name = {                                \
@@ -871,6 +872,7 @@ static struct clk atmel_psif1_pclk = {
 struct platform_device *__init at32_add_device_psif(unsigned int id)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (!(id == 0 || id == 1))
                return NULL;
@@ -881,20 +883,22 @@ struct platform_device *__init at32_add_device_psif(unsigned int id)
 
        switch (id) {
        case 0:
+               pin_mask  = (1 << 8) | (1 << 9); /* CLOCK & DATA */
+
                if (platform_device_add_resources(pdev, atmel_psif0_resource,
                                        ARRAY_SIZE(atmel_psif0_resource)))
                        goto err_add_resources;
                atmel_psif0_pclk.dev = &pdev->dev;
-               select_peripheral(PA(8), PERIPH_A, 0); /* CLOCK */
-               select_peripheral(PA(9), PERIPH_A, 0); /* DATA  */
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
                break;
        case 1:
+               pin_mask  = (1 << 11) | (1 << 12); /* CLOCK & DATA */
+
                if (platform_device_add_resources(pdev, atmel_psif1_resource,
                                        ARRAY_SIZE(atmel_psif1_resource)))
                        goto err_add_resources;
                atmel_psif1_pclk.dev = &pdev->dev;
-               select_peripheral(PB(11), PERIPH_A, 0); /* CLOCK */
-               select_peripheral(PB(12), PERIPH_A, 0); /* DATA  */
+               select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
                break;
        default:
                return NULL;
@@ -958,26 +962,30 @@ DEV_CLK(usart, atmel_usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
-       select_peripheral(PA(8),  PERIPH_B, 0); /* RXD  */
-       select_peripheral(PA(9),  PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 8) | (1 << 9); /* RXD & TXD */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart1_pins(void)
 {
-       select_peripheral(PA(17), PERIPH_A, 0); /* RXD  */
-       select_peripheral(PA(18), PERIPH_A, 0); /* TXD  */
+       u32 pin_mask = (1 << 17) | (1 << 18); /* RXD & TXD */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 }
 
 static inline void configure_usart2_pins(void)
 {
-       select_peripheral(PB(26), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(27), PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 26) | (1 << 27); /* RXD & TXD */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static inline void configure_usart3_pins(void)
 {
-       select_peripheral(PB(18), PERIPH_B, 0); /* RXD  */
-       select_peripheral(PB(17), PERIPH_B, 0); /* TXD  */
+       u32 pin_mask = (1 << 18) | (1 << 17); /* RXD & TXD */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 }
 
 static struct platform_device *__initdata at32_usarts[4];
@@ -1057,59 +1065,69 @@ struct platform_device *__init
 at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        switch (id) {
        case 0:
                pdev = &macb0_device;
 
-               select_peripheral(PC(3),  PERIPH_A, 0); /* TXD0 */
-               select_peripheral(PC(4),  PERIPH_A, 0); /* TXD1 */
-               select_peripheral(PC(7),  PERIPH_A, 0); /* TXEN */
-               select_peripheral(PC(8),  PERIPH_A, 0); /* TXCK */
-               select_peripheral(PC(9),  PERIPH_A, 0); /* RXD0 */
-               select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
-               select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
-               select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
-               select_peripheral(PC(16), PERIPH_A, 0); /* MDC  */
-               select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
+               pin_mask  = (1 << 3);   /* TXD0 */
+               pin_mask |= (1 << 4);   /* TXD1 */
+               pin_mask |= (1 << 7);   /* TXEN */
+               pin_mask |= (1 << 8);   /* TXCK */
+               pin_mask |= (1 << 9);   /* RXD0 */
+               pin_mask |= (1 << 10);  /* RXD1 */
+               pin_mask |= (1 << 13);  /* RXER */
+               pin_mask |= (1 << 15);  /* RXDV */
+               pin_mask |= (1 << 16);  /* MDC  */
+               pin_mask |= (1 << 17);  /* MDIO */
 
                if (!data->is_rmii) {
-                       select_peripheral(PC(0),  PERIPH_A, 0); /* COL  */
-                       select_peripheral(PC(1),  PERIPH_A, 0); /* CRS  */
-                       select_peripheral(PC(2),  PERIPH_A, 0); /* TXER */
-                       select_peripheral(PC(5),  PERIPH_A, 0); /* TXD2 */
-                       select_peripheral(PC(6),  PERIPH_A, 0); /* TXD3 */
-                       select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
-                       select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
-                       select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
-                       select_peripheral(PC(18), PERIPH_A, 0); /* SPD  */
+                       pin_mask |= (1 << 0);   /* COL  */
+                       pin_mask |= (1 << 1);   /* CRS  */
+                       pin_mask |= (1 << 2);   /* TXER */
+                       pin_mask |= (1 << 5);   /* TXD2 */
+                       pin_mask |= (1 << 6);   /* TXD3 */
+                       pin_mask |= (1 << 11);  /* RXD2 */
+                       pin_mask |= (1 << 12);  /* RXD3 */
+                       pin_mask |= (1 << 14);  /* RXCK */
+                       pin_mask |= (1 << 18);  /* SPD  */
                }
+
+               select_peripheral(PIOC, pin_mask, PERIPH_A, 0);
+
                break;
 
        case 1:
                pdev = &macb1_device;
 
-               select_peripheral(PD(13), PERIPH_B, 0);         /* TXD0 */
-               select_peripheral(PD(14), PERIPH_B, 0);         /* TXD1 */
-               select_peripheral(PD(11), PERIPH_B, 0);         /* TXEN */
-               select_peripheral(PD(12), PERIPH_B, 0);         /* TXCK */
-               select_peripheral(PD(10), PERIPH_B, 0);         /* RXD0 */
-               select_peripheral(PD(6),  PERIPH_B, 0);         /* RXD1 */
-               select_peripheral(PD(5),  PERIPH_B, 0);         /* RXER */
-               select_peripheral(PD(4),  PERIPH_B, 0);         /* RXDV */
-               select_peripheral(PD(3),  PERIPH_B, 0);         /* MDC  */
-               select_peripheral(PD(2),  PERIPH_B, 0);         /* MDIO */
+               pin_mask  = (1 << 13);  /* TXD0 */
+               pin_mask |= (1 << 14);  /* TXD1 */
+               pin_mask |= (1 << 11);  /* TXEN */
+               pin_mask |= (1 << 12);  /* TXCK */
+               pin_mask |= (1 << 10);  /* RXD0 */
+               pin_mask |= (1 << 6);   /* RXD1 */
+               pin_mask |= (1 << 5);   /* RXER */
+               pin_mask |= (1 << 4);   /* RXDV */
+               pin_mask |= (1 << 3);   /* MDC  */
+               pin_mask |= (1 << 2);   /* MDIO */
+
+               if (!data->is_rmii)
+                       pin_mask |= (1 << 15);  /* SPD  */
+
+               select_peripheral(PIOD, pin_mask, PERIPH_B, 0);
 
                if (!data->is_rmii) {
-                       select_peripheral(PC(19), PERIPH_B, 0); /* COL  */
-                       select_peripheral(PC(23), PERIPH_B, 0); /* CRS  */
-                       select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
-                       select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
-                       select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
-                       select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
-                       select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
-                       select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
-                       select_peripheral(PD(15), PERIPH_B, 0); /* SPD  */
+                       pin_mask  = (1 << 19);  /* COL  */
+                       pin_mask |= (1 << 23);  /* CRS  */
+                       pin_mask |= (1 << 26);  /* TXER */
+                       pin_mask |= (1 << 27);  /* TXD2 */
+                       pin_mask |= (1 << 28);  /* TXD3 */
+                       pin_mask |= (1 << 29);  /* RXD2 */
+                       pin_mask |= (1 << 30);  /* RXD3 */
+                       pin_mask |= (1 << 24);  /* RXCK */
+
+                       select_peripheral(PIOC, pin_mask, PERIPH_B, 0);
                }
                break;
 
@@ -1177,23 +1195,28 @@ at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
                { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
                  GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
        struct platform_device *pdev;
+       u32 pin_mask;
 
        switch (id) {
        case 0:
                pdev = &atmel_spi0_device;
+               pin_mask  = (1 << 1) | (1 << 2);        /* MOSI & SCK */
+
                /* pullup MISO so a level is always defined */
-               select_peripheral(PA(0),  PERIPH_A, AT32_GPIOF_PULLUP);
-               select_peripheral(PA(1),  PERIPH_A, 0); /* MOSI  */
-               select_peripheral(PA(2),  PERIPH_A, 0); /* SCK   */
+               select_peripheral(PIOA, (1 << 0), PERIPH_A, AT32_GPIOF_PULLUP);
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
                at32_spi_setup_slaves(0, b, n, spi0_pins);
                break;
 
        case 1:
                pdev = &atmel_spi1_device;
+               pin_mask  = (1 << 1) | (1 << 5);        /* MOSI */
+
                /* pullup MISO so a level is always defined */
-               select_peripheral(PB(0),  PERIPH_B, AT32_GPIOF_PULLUP);
-               select_peripheral(PB(1),  PERIPH_B, 0); /* MOSI  */
-               select_peripheral(PB(5),  PERIPH_B, 0); /* SCK   */
+               select_peripheral(PIOB, (1 << 0), PERIPH_B, AT32_GPIOF_PULLUP);
+               select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
+
                at32_spi_setup_slaves(1, b, n, spi1_pins);
                break;
 
@@ -1226,6 +1249,7 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
                                                    unsigned int n)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -1238,8 +1262,9 @@ struct platform_device *__init at32_add_device_twi(unsigned int id,
                                ARRAY_SIZE(atmel_twi0_resource)))
                goto err_add_resources;
 
-       select_peripheral(PA(6),  PERIPH_A, 0); /* SDA  */
-       select_peripheral(PA(7),  PERIPH_A, 0); /* SDL  */
+       pin_mask  = (1 << 6) | (1 << 7);        /* SDA & SDL */
+
+       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
 
        atmel_twi0_pclk.dev = &pdev->dev;
 
@@ -1272,10 +1297,16 @@ static struct clk atmel_mci0_pclk = {
 struct platform_device *__init
 at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
 {
-       struct mci_platform_data        _data;
        struct platform_device          *pdev;
+       struct dw_dma_slave             *dws;
+       u32                             pioa_mask;
+       u32                             piob_mask;
 
-       if (id != 0)
+       if (id != 0 || !data)
+               return NULL;
+
+       /* Must have at least one usable slot */
+       if (!data->slot[0].bus_width && !data->slot[1].bus_width)
                return NULL;
 
        pdev = platform_device_alloc("atmel_mci", id);
@@ -1286,28 +1317,80 @@ at32_add_device_mci(unsigned int id, struct mci_platform_data *data)
                                ARRAY_SIZE(atmel_mci0_resource)))
                goto fail;
 
-       if (!data) {
-               data = &_data;
-               memset(data, -1, sizeof(struct mci_platform_data));
-               data->detect_pin = GPIO_PIN_NONE;
-               data->wp_pin = GPIO_PIN_NONE;
-       }
+       if (data->dma_slave)
+               dws = kmemdup(to_dw_dma_slave(data->dma_slave),
+                               sizeof(struct dw_dma_slave), GFP_KERNEL);
+       else
+               dws = kzalloc(sizeof(struct dw_dma_slave), GFP_KERNEL);
+
+       dws->slave.dev = &pdev->dev;
+       dws->slave.dma_dev = &dw_dmac0_device.dev;
+       dws->slave.reg_width = DMA_SLAVE_WIDTH_32BIT;
+       dws->cfg_hi = (DWC_CFGH_SRC_PER(0)
+                               | DWC_CFGH_DST_PER(1));
+       dws->cfg_lo &= ~(DWC_CFGL_HS_DST_POL
+                               | DWC_CFGL_HS_SRC_POL);
+
+       data->dma_slave = &dws->slave;
 
        if (platform_device_add_data(pdev, data,
                                sizeof(struct mci_platform_data)))
                goto fail;
 
-       select_peripheral(PA(10), PERIPH_A, 0); /* CLK   */
-       select_peripheral(PA(11), PERIPH_A, 0); /* CMD   */
-       select_peripheral(PA(12), PERIPH_A, 0); /* DATA0 */
-       select_peripheral(PA(13), PERIPH_A, 0); /* DATA1 */
-       select_peripheral(PA(14), PERIPH_A, 0); /* DATA2 */
-       select_peripheral(PA(15), PERIPH_A, 0); /* DATA3 */
+       /* CLK line is common to both slots */
+       pioa_mask = 1 << 10;
 
-       if (gpio_is_valid(data->detect_pin))
-               at32_select_gpio(data->detect_pin, 0);
-       if (gpio_is_valid(data->wp_pin))
-               at32_select_gpio(data->wp_pin, 0);
+       switch (data->slot[0].bus_width) {
+       case 4:
+               pioa_mask |= 1 << 13;           /* DATA1 */
+               pioa_mask |= 1 << 14;           /* DATA2 */
+               pioa_mask |= 1 << 15;           /* DATA3 */
+               /* fall through */
+       case 1:
+               pioa_mask |= 1 << 11;           /* CMD   */
+               pioa_mask |= 1 << 12;           /* DATA0 */
+
+               if (gpio_is_valid(data->slot[0].detect_pin))
+                       at32_select_gpio(data->slot[0].detect_pin, 0);
+               if (gpio_is_valid(data->slot[0].wp_pin))
+                       at32_select_gpio(data->slot[0].wp_pin, 0);
+               break;
+       case 0:
+               /* Slot is unused */
+               break;
+       default:
+               goto fail;
+       }
+
+       select_peripheral(PIOA, pioa_mask, PERIPH_A, 0);
+       piob_mask = 0;
+
+       switch (data->slot[1].bus_width) {
+       case 4:
+               piob_mask |= 1 <<  8;           /* DATA1 */
+               piob_mask |= 1 <<  9;           /* DATA2 */
+               piob_mask |= 1 << 10;           /* DATA3 */
+               /* fall through */
+       case 1:
+               piob_mask |= 1 <<  6;           /* CMD   */
+               piob_mask |= 1 <<  7;           /* DATA0 */
+               select_peripheral(PIOB, piob_mask, PERIPH_B, 0);
+
+               if (gpio_is_valid(data->slot[1].detect_pin))
+                       at32_select_gpio(data->slot[1].detect_pin, 0);
+               if (gpio_is_valid(data->slot[1].wp_pin))
+                       at32_select_gpio(data->slot[1].wp_pin, 0);
+               break;
+       case 0:
+               /* Slot is unused */
+               break;
+       default:
+               if (!data->slot[0].bus_width)
+                       goto fail;
+
+               data->slot[1].bus_width = 0;
+               break;
+       }
 
        atmel_mci0_pclk.dev = &pdev->dev;
 
@@ -1353,13 +1436,14 @@ static struct clk atmel_lcdfb0_pixclk = {
 struct platform_device *__init
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
-                    unsigned int pin_config)
+                    u64 pin_mask)
 {
        struct platform_device *pdev;
        struct atmel_lcdfb_info *info;
        struct fb_monspecs *monspecs;
        struct fb_videomode *modedb;
        unsigned int modedb_size;
+       u32 portc_mask, portd_mask, porte_mask;
 
        /*
         * Do a deep copy of the fb data, monspecs and modedb. Make
@@ -1381,76 +1465,21 @@ at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
        case 0:
                pdev = &atmel_lcdfb0_device;
 
-               switch (pin_config) {
-               case 0:
-                       select_peripheral(PC(19), PERIPH_A, 0); /* CC     */
-                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-                       select_peripheral(PC(23), PERIPH_A, 0); /* DVAL   */
-                       select_peripheral(PC(24), PERIPH_A, 0); /* MODE   */
-                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-                       select_peripheral(PC(26), PERIPH_A, 0); /* DATA0  */
-                       select_peripheral(PC(27), PERIPH_A, 0); /* DATA1  */
-                       select_peripheral(PC(28), PERIPH_A, 0); /* DATA2  */
-                       select_peripheral(PC(29), PERIPH_A, 0); /* DATA3  */
-                       select_peripheral(PC(30), PERIPH_A, 0); /* DATA4  */
-                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-                       select_peripheral(PD(2),  PERIPH_A, 0); /* DATA8  */
-                       select_peripheral(PD(3),  PERIPH_A, 0); /* DATA9  */
-                       select_peripheral(PD(4),  PERIPH_A, 0); /* DATA10 */
-                       select_peripheral(PD(5),  PERIPH_A, 0); /* DATA11 */
-                       select_peripheral(PD(6),  PERIPH_A, 0); /* DATA12 */
-                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-                       select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
-                       select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
-                       select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
-                       select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
-                       select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
-                       select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
-                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-                       break;
-               case 1:
-                       select_peripheral(PE(0),  PERIPH_B, 0); /* CC     */
-                       select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC  */
-                       select_peripheral(PC(21), PERIPH_A, 0); /* PCLK   */
-                       select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC  */
-                       select_peripheral(PE(1),  PERIPH_B, 0); /* DVAL   */
-                       select_peripheral(PE(2),  PERIPH_B, 0); /* MODE   */
-                       select_peripheral(PC(25), PERIPH_A, 0); /* PWR    */
-                       select_peripheral(PE(3),  PERIPH_B, 0); /* DATA0  */
-                       select_peripheral(PE(4),  PERIPH_B, 0); /* DATA1  */
-                       select_peripheral(PE(5),  PERIPH_B, 0); /* DATA2  */
-                       select_peripheral(PE(6),  PERIPH_B, 0); /* DATA3  */
-                       select_peripheral(PE(7),  PERIPH_B, 0); /* DATA4  */
-                       select_peripheral(PC(31), PERIPH_A, 0); /* DATA5  */
-                       select_peripheral(PD(0),  PERIPH_A, 0); /* DATA6  */
-                       select_peripheral(PD(1),  PERIPH_A, 0); /* DATA7  */
-                       select_peripheral(PE(8),  PERIPH_B, 0); /* DATA8  */
-                       select_peripheral(PE(9),  PERIPH_B, 0); /* DATA9  */
-                       select_peripheral(PE(10), PERIPH_B, 0); /* DATA10 */
-                       select_peripheral(PE(11), PERIPH_B, 0); /* DATA11 */
-                       select_peripheral(PE(12), PERIPH_B, 0); /* DATA12 */
-                       select_peripheral(PD(7),  PERIPH_A, 0); /* DATA13 */
-                       select_peripheral(PD(8),  PERIPH_A, 0); /* DATA14 */
-                       select_peripheral(PD(9),  PERIPH_A, 0); /* DATA15 */
-                       select_peripheral(PE(13), PERIPH_B, 0); /* DATA16 */
-                       select_peripheral(PE(14), PERIPH_B, 0); /* DATA17 */
-                       select_peripheral(PE(15), PERIPH_B, 0); /* DATA18 */
-                       select_peripheral(PE(16), PERIPH_B, 0); /* DATA19 */
-                       select_peripheral(PE(17), PERIPH_B, 0); /* DATA20 */
-                       select_peripheral(PE(18), PERIPH_B, 0); /* DATA21 */
-                       select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
-                       select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
-                       break;
-               default:
-                       goto err_invalid_id;
-               }
+               if (pin_mask == 0ULL)
+                       /* Default to "full" lcdc control signals and 24bit */
+                       pin_mask = ATMEL_LCDC_PRI_24BIT | ATMEL_LCDC_PRI_CONTROL;
+
+               /* LCDC on port C */
+               portc_mask = (pin_mask & 0xfff80000) >> 19;
+               select_peripheral(PIOC, portc_mask, PERIPH_A, 0);
+
+               /* LCDC on port D */
+               portd_mask = pin_mask & 0x0003ffff;
+               select_peripheral(PIOD, portd_mask, PERIPH_A, 0);
+
+               /* LCDC on port E */
+               porte_mask = (pin_mask >> 32) & 0x0007ffff;
+               select_peripheral(PIOE, porte_mask, PERIPH_B, 0);
 
                clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
                clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
@@ -1499,6 +1528,7 @@ static struct clk atmel_pwm0_mck = {
 struct platform_device *__init at32_add_device_pwm(u32 mask)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (!mask)
                return NULL;
@@ -1514,14 +1544,21 @@ struct platform_device *__init at32_add_device_pwm(u32 mask)
        if (platform_device_add_data(pdev, &mask, sizeof(mask)))
                goto out_free_pdev;
 
+       pin_mask = 0;
        if (mask & (1 << 0))
-               select_peripheral(PA(28), PERIPH_A, 0);
+               pin_mask |= (1 << 28);
        if (mask & (1 << 1))
-               select_peripheral(PA(29), PERIPH_A, 0);
+               pin_mask |= (1 << 29);
+       if (pin_mask > 0)
+               select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
+       pin_mask = 0;
        if (mask & (1 << 2))
-               select_peripheral(PA(21), PERIPH_B, 0);
+               pin_mask |= (1 << 21);
        if (mask & (1 << 3))
-               select_peripheral(PA(22), PERIPH_B, 0);
+               pin_mask |= (1 << 22);
+       if (pin_mask > 0)
+               select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
 
        atmel_pwm0_mck.dev = &pdev->dev;
 
@@ -1562,52 +1599,65 @@ struct platform_device *__init
 at32_add_device_ssc(unsigned int id, unsigned int flags)
 {
        struct platform_device *pdev;
+       u32 pin_mask = 0;
 
        switch (id) {
        case 0:
                pdev = &ssc0_device;
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+                       pin_mask |= (1 << 21);  /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+                       pin_mask |= (1 << 22);  /* RK */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+                       pin_mask |= (1 << 23);  /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+                       pin_mask |= (1 << 24);  /* TF */
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+                       pin_mask |= (1 << 25);  /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+                       pin_mask |= (1 << 26);  /* RD */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOA, pin_mask, PERIPH_A, 0);
+
                break;
        case 1:
                pdev = &ssc1_device;
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PA(0), PERIPH_B, 0);  /* RF */
+                       pin_mask |= (1 << 0);   /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PA(1), PERIPH_B, 0);  /* RK */
+                       pin_mask |= (1 << 1);   /* RK */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PA(2), PERIPH_B, 0);  /* TK */
+                       pin_mask |= (1 << 2);   /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PA(3), PERIPH_B, 0);  /* TF */
+                       pin_mask |= (1 << 3);   /* TF */
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PA(4), PERIPH_B, 0);  /* TD */
+                       pin_mask |= (1 << 4);   /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PA(5), PERIPH_B, 0);  /* RD */
+                       pin_mask |= (1 << 5);   /* RD */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOA, pin_mask, PERIPH_B, 0);
+
                break;
        case 2:
                pdev = &ssc2_device;
                if (flags & ATMEL_SSC_TD)
-                       select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+                       pin_mask |= (1 << 13);  /* TD */
                if (flags & ATMEL_SSC_RD)
-                       select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+                       pin_mask |= (1 << 14);  /* RD */
                if (flags & ATMEL_SSC_TK)
-                       select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+                       pin_mask |= (1 << 15);  /* TK */
                if (flags & ATMEL_SSC_TF)
-                       select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+                       pin_mask |= (1 << 16);  /* TF */
                if (flags & ATMEL_SSC_RF)
-                       select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+                       pin_mask |= (1 << 17);  /* RF */
                if (flags & ATMEL_SSC_RK)
-                       select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+                       pin_mask |= (1 << 18);  /* RK */
+
+               if (pin_mask > 0)
+                       select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
+
                break;
        default:
                return NULL;
@@ -1745,14 +1795,15 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                unsigned int cs, unsigned int extint)
 {
        static unsigned int extint_pin_map[4] __initdata = {
-               GPIO_PIN_PB(25),
-               GPIO_PIN_PB(26),
-               GPIO_PIN_PB(27),
-               GPIO_PIN_PB(28),
+               (1 << 25),
+               (1 << 26),
+               (1 << 27),
+               (1 << 28),
        };
        static bool common_pins_initialized __initdata = false;
        unsigned int extint_pin;
        int ret;
+       u32 pin_mask;
 
        if (extint >= ARRAY_SIZE(extint_pin_map))
                return -EINVAL;
@@ -1766,7 +1817,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                if (ret)
                        return ret;
 
-               select_peripheral(PE(21), PERIPH_A, 0); /* NCS4   -> OE_N  */
+               /* NCS4   -> OE_N  */
+               select_peripheral(PIOE, (1 << 21), PERIPH_A, 0);
                hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF0_ENABLE);
                break;
        case 5:
@@ -1776,7 +1828,8 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
                if (ret)
                        return ret;
 
-               select_peripheral(PE(22), PERIPH_A, 0); /* NCS5   -> OE_N  */
+               /* NCS5   -> OE_N  */
+               select_peripheral(PIOE, (1 << 22), PERIPH_A, 0);
                hmatrix_sfr_set_bits(HMATRIX_SLAVE_EBI, HMATRIX_EBI_CF1_ENABLE);
                break;
        default:
@@ -1784,14 +1837,17 @@ static int __init at32_init_ide_or_cf(struct platform_device *pdev,
        }
 
        if (!common_pins_initialized) {
-               select_peripheral(PE(19), PERIPH_A, 0); /* CFCE1  -> CS0_N */
-               select_peripheral(PE(20), PERIPH_A, 0); /* CFCE2  -> CS1_N */
-               select_peripheral(PE(23), PERIPH_A, 0); /* CFRNW  -> DIR   */
-               select_peripheral(PE(24), PERIPH_A, 0); /* NWAIT  <- IORDY */
+               pin_mask  = (1 << 19);  /* CFCE1  -> CS0_N */
+               pin_mask |= (1 << 20);  /* CFCE2  -> CS1_N */
+               pin_mask |= (1 << 23);  /* CFRNW  -> DIR   */
+               pin_mask |= (1 << 24);  /* NWAIT  <- IORDY */
+
+               select_peripheral(PIOE, pin_mask, PERIPH_A, 0);
+
                common_pins_initialized = true;
        }
 
-       at32_select_periph(extint_pin, GPIO_PERIPH_A, AT32_GPIOF_DEGLITCH);
+       select_peripheral(PIOB, extint_pin, PERIPH_A, AT32_GPIOF_DEGLITCH);
 
        pdev->resource[1].start = EIM_IRQ_BASE + extint;
        pdev->resource[1].end = pdev->resource[1].start;
@@ -1930,6 +1986,7 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
 {
        struct platform_device *pdev;
        struct ac97c_platform_data _data;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -1956,10 +2013,10 @@ at32_add_device_ac97c(unsigned int id, struct ac97c_platform_data *data)
                                sizeof(struct ac97c_platform_data)))
                goto fail;
 
-       select_peripheral(PB(20), PERIPH_B, 0); /* SDO  */
-       select_peripheral(PB(21), PERIPH_B, 0); /* SYNC */
-       select_peripheral(PB(22), PERIPH_B, 0); /* SCLK */
-       select_peripheral(PB(23), PERIPH_B, 0); /* SDI  */
+       pin_mask  = (1 << 20) | (1 << 21);      /* SDO & SYNC */
+       pin_mask |= (1 << 22) | (1 << 23);      /* SCLK & SDI */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_B, 0);
 
        /* TODO: gpio_is_valid(data->reset_pin) with kernel 2.6.26. */
        if (data->reset_pin != GPIO_PIN_NONE)
@@ -2001,6 +2058,7 @@ static struct clk abdac0_sample_clk = {
 struct platform_device *__init at32_add_device_abdac(unsigned int id)
 {
        struct platform_device *pdev;
+       u32 pin_mask;
 
        if (id != 0)
                return NULL;
@@ -2013,10 +2071,10 @@ struct platform_device *__init at32_add_device_abdac(unsigned int id)
                                ARRAY_SIZE(abdac0_resource)))
                goto err_add_resources;
 
-       select_peripheral(PB(20), PERIPH_A, 0); /* DATA1        */
-       select_peripheral(PB(21), PERIPH_A, 0); /* DATA0        */
-       select_peripheral(PB(22), PERIPH_A, 0); /* DATAN1       */
-       select_peripheral(PB(23), PERIPH_A, 0); /* DATAN0       */
+       pin_mask  = (1 << 20) | (1 << 22);      /* DATA1 & DATAN1 */
+       pin_mask |= (1 << 21) | (1 << 23);      /* DATA0 & DATAN0 */
+
+       select_peripheral(PIOB, pin_mask, PERIPH_A, 0);
 
        abdac0_pclk.dev = &pdev->dev;
        abdac0_sample_clk.dev = &pdev->dev;
@@ -2073,7 +2131,7 @@ static struct clk gclk4 = {
        .index          = 4,
 };
 
-struct clk *at32_clock_list[] = {
+static __initdata struct clk *init_clocks[] = {
        &osc32k,
        &osc0,
        &osc1,
@@ -2137,7 +2195,6 @@ struct clk *at32_clock_list[] = {
        &gclk3,
        &gclk4,
 };
-unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
 
 void __init setup_platform(void)
 {
@@ -2168,14 +2225,19 @@ void __init setup_platform(void)
        genclk_init_parent(&abdac0_sample_clk);
 
        /*
-        * Turn on all clocks that have at least one user already, and
-        * turn off everything else. We only do this for module
-        * clocks, and even though it isn't particularly pretty to
-        * check the address of the mode function, it should do the
-        * trick...
+        * Build initial dynamic clock list by registering all clocks
+        * from the array.
+        * At the same time, turn on all clocks that have at least one
+        * user already, and turn off everything else. We only do this
+        * for module clocks, and even though it isn't particularly
+        * pretty to  check the address of the mode function, it should
+        * do the trick...
         */
-       for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
-               struct clk *clk = at32_clock_list[i];
+       for (i = 0; i < ARRAY_SIZE(init_clocks); i++) {
+               struct clk *clk = init_clocks[i];
+
+               /* first, register clock */
+               at32_clk_register(clk);
 
                if (clk->users == 0)
                        continue;
index 6c27ddac5adf10c6870c1c4679f8f6ab93411dc8..138a00a2a2d0c5c833723a0a6610e8baf6d42a5c 100644 (file)
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/list.h>
 
 #include <mach/chip.h>
 
 #include "clock.h"
 
+/* at32 clock list */
+static LIST_HEAD(at32_clock_list);
+
 static DEFINE_SPINLOCK(clk_lock);
+static DEFINE_SPINLOCK(clk_list_lock);
+
+void at32_clk_register(struct clk *clk)
+{
+       spin_lock(&clk_list_lock);
+       /* add the new item to the end of the list */
+       list_add_tail(&clk->list, &at32_clock_list);
+       spin_unlock(&clk_list_lock);
+}
 
 struct clk *clk_get(struct device *dev, const char *id)
 {
-       int i;
+       struct clk *clk;
 
-       for (i = 0; i < at32_nr_clocks; i++) {
-               struct clk *clk = at32_clock_list[i];
+       spin_lock(&clk_list_lock);
 
-               if (clk->dev == dev && strcmp(id, clk->name) == 0)
+       list_for_each_entry(clk, &at32_clock_list, list) {
+               if (clk->dev == dev && strcmp(id, clk->name) == 0) {
+                       spin_unlock(&clk_list_lock);
                        return clk;
+               }
        }
 
+       spin_unlock(&clk_list_lock);
        return ERR_PTR(-ENOENT);
 }
 EXPORT_SYMBOL(clk_get);
@@ -203,8 +219,8 @@ dump_clock(struct clk *parent, struct clkinf *r)
 
        /* cost of this scan is small, but not linear... */
        r->nest = nest + NEST_DELTA;
-       for (i = 3; i < at32_nr_clocks; i++) {
-               clk = at32_clock_list[i];
+
+       list_for_each_entry(clk, &at32_clock_list, list) {
                if (clk->parent == parent)
                        dump_clock(clk, r);
        }
@@ -215,6 +231,7 @@ static int clk_show(struct seq_file *s, void *unused)
 {
        struct clkinf   r;
        int             i;
+       struct clk      *clk;
 
        /* show all the power manager registers */
        seq_printf(s, "MCCTRL  = %8x\n", pm_readl(MCCTRL));
@@ -234,14 +251,25 @@ static int clk_show(struct seq_file *s, void *unused)
 
        seq_printf(s, "\n");
 
-       /* show clock tree as derived from the three oscillators
-        * we "know" are at the head of the list
-        */
        r.s = s;
        r.nest = 0;
-       dump_clock(at32_clock_list[0], &r);
-       dump_clock(at32_clock_list[1], &r);
-       dump_clock(at32_clock_list[2], &r);
+       /* protected from changes on the list while dumping */
+       spin_lock(&clk_list_lock);
+
+       /* show clock tree as derived from the three oscillators */
+       clk = clk_get(NULL, "osc32k");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       clk = clk_get(NULL, "osc0");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       clk = clk_get(NULL, "osc1");
+       dump_clock(clk, &r);
+       clk_put(clk);
+
+       spin_unlock(&clk_list_lock);
 
        return 0;
 }
index bb8e1f295835e95fa306c42071a6d5c55fe4fe3b..623bf0e9a1e7a843ff66c02ed0aa4961dc3b784d 100644 (file)
  * published by the Free Software Foundation.
  */
 #include <linux/clk.h>
+#include <linux/list.h>
+
+
+void at32_clk_register(struct clk *clk);
 
 struct clk {
+       struct list_head list;          /* linking element */
        const char      *name;          /* Clock name/function */
        struct device   *dev;           /* Device the clock is used by */
        struct clk      *parent;        /* Parent clock, if any */
@@ -25,6 +30,3 @@ struct clk {
        u16             users;          /* Enabled if non-zero */
        u16             index;          /* Sibling index */
 };
-
-extern struct clk *at32_clock_list[];
-extern unsigned int at32_nr_clocks;
index 1e9852d65ccaf04256dc96df8968984c772e692a..a77d372f6f3ea8660ffeec96cc31b52381a04b77 100644 (file)
 #define HMATRIX_BASE   0xfff00800
 #define SDRAMC_BASE    0xfff03800
 
+/* LCDC on port C */
+#define ATMEL_LCDC_PC_CC       (1ULL << 19)
+#define ATMEL_LCDC_PC_HSYNC    (1ULL << 20)
+#define ATMEL_LCDC_PC_PCLK     (1ULL << 21)
+#define ATMEL_LCDC_PC_VSYNC    (1ULL << 22)
+#define ATMEL_LCDC_PC_DVAL     (1ULL << 23)
+#define ATMEL_LCDC_PC_MODE     (1ULL << 24)
+#define ATMEL_LCDC_PC_PWR      (1ULL << 25)
+#define ATMEL_LCDC_PC_DATA0    (1ULL << 26)
+#define ATMEL_LCDC_PC_DATA1    (1ULL << 27)
+#define ATMEL_LCDC_PC_DATA2    (1ULL << 28)
+#define ATMEL_LCDC_PC_DATA3    (1ULL << 29)
+#define ATMEL_LCDC_PC_DATA4    (1ULL << 30)
+#define ATMEL_LCDC_PC_DATA5    (1ULL << 31)
+
+/* LCDC on port D */
+#define ATMEL_LCDC_PD_DATA6    (1ULL << 0)
+#define ATMEL_LCDC_PD_DATA7    (1ULL << 1)
+#define ATMEL_LCDC_PD_DATA8    (1ULL << 2)
+#define ATMEL_LCDC_PD_DATA9    (1ULL << 3)
+#define ATMEL_LCDC_PD_DATA10   (1ULL << 4)
+#define ATMEL_LCDC_PD_DATA11   (1ULL << 5)
+#define ATMEL_LCDC_PD_DATA12   (1ULL << 6)
+#define ATMEL_LCDC_PD_DATA13   (1ULL << 7)
+#define ATMEL_LCDC_PD_DATA14   (1ULL << 8)
+#define ATMEL_LCDC_PD_DATA15   (1ULL << 9)
+#define ATMEL_LCDC_PD_DATA16   (1ULL << 10)
+#define ATMEL_LCDC_PD_DATA17   (1ULL << 11)
+#define ATMEL_LCDC_PD_DATA18   (1ULL << 12)
+#define ATMEL_LCDC_PD_DATA19   (1ULL << 13)
+#define ATMEL_LCDC_PD_DATA20   (1ULL << 14)
+#define ATMEL_LCDC_PD_DATA21   (1ULL << 15)
+#define ATMEL_LCDC_PD_DATA22   (1ULL << 16)
+#define ATMEL_LCDC_PD_DATA23   (1ULL << 17)
+
+/* LCDC on port E */
+#define ATMEL_LCDC_PE_CC       (1ULL << (32 + 0))
+#define ATMEL_LCDC_PE_DVAL     (1ULL << (32 + 1))
+#define ATMEL_LCDC_PE_MODE     (1ULL << (32 + 2))
+#define ATMEL_LCDC_PE_DATA0    (1ULL << (32 + 3))
+#define ATMEL_LCDC_PE_DATA1    (1ULL << (32 + 4))
+#define ATMEL_LCDC_PE_DATA2    (1ULL << (32 + 5))
+#define ATMEL_LCDC_PE_DATA3    (1ULL << (32 + 6))
+#define ATMEL_LCDC_PE_DATA4    (1ULL << (32 + 7))
+#define ATMEL_LCDC_PE_DATA8    (1ULL << (32 + 8))
+#define ATMEL_LCDC_PE_DATA9    (1ULL << (32 + 9))
+#define ATMEL_LCDC_PE_DATA10   (1ULL << (32 + 10))
+#define ATMEL_LCDC_PE_DATA11   (1ULL << (32 + 11))
+#define ATMEL_LCDC_PE_DATA12   (1ULL << (32 + 12))
+#define ATMEL_LCDC_PE_DATA16   (1ULL << (32 + 13))
+#define ATMEL_LCDC_PE_DATA17   (1ULL << (32 + 14))
+#define ATMEL_LCDC_PE_DATA18   (1ULL << (32 + 15))
+#define ATMEL_LCDC_PE_DATA19   (1ULL << (32 + 16))
+#define ATMEL_LCDC_PE_DATA20   (1ULL << (32 + 17))
+#define ATMEL_LCDC_PE_DATA21   (1ULL << (32 + 18))
+
+
+#define ATMEL_LCDC(PORT, PIN)  (ATMEL_LCDC_##PORT##_##PIN)
+
+
+#define ATMEL_LCDC_PRI_24B_DATA        (                                       \
+               ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |       \
+               ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |       \
+               ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |       \
+               ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |       \
+               ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |       \
+               ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA13) |       \
+               ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |       \
+               ATMEL_LCDC(PD, DATA16) | ATMEL_LCDC(PD, DATA17) |       \
+               ATMEL_LCDC(PD, DATA18) | ATMEL_LCDC(PD, DATA19) |       \
+               ATMEL_LCDC(PD, DATA20) | ATMEL_LCDC(PD, DATA21) |       \
+               ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_ALT_24B_DATA (                                      \
+               ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |       \
+               ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |       \
+               ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA6)  | ATMEL_LCDC(PD, DATA7)  |       \
+               ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |       \
+               ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |       \
+               ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PD, DATA13) |       \
+               ATMEL_LCDC(PD, DATA14) | ATMEL_LCDC(PD, DATA15) |       \
+               ATMEL_LCDC(PE, DATA16) | ATMEL_LCDC(PE, DATA17) |       \
+               ATMEL_LCDC(PE, DATA18) | ATMEL_LCDC(PE, DATA19) |       \
+               ATMEL_LCDC(PE, DATA20) | ATMEL_LCDC(PE, DATA21) |       \
+               ATMEL_LCDC(PD, DATA22) | ATMEL_LCDC(PD, DATA23))
+
+#define ATMEL_LCDC_PRI_15B_DATA (                                      \
+               ATMEL_LCDC(PC, DATA0)  | ATMEL_LCDC(PC, DATA1)  |       \
+               ATMEL_LCDC(PC, DATA2)  | ATMEL_LCDC(PC, DATA3)  |       \
+               ATMEL_LCDC(PC, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PD, DATA8)  | ATMEL_LCDC(PD, DATA9)  |       \
+               ATMEL_LCDC(PD, DATA10) | ATMEL_LCDC(PD, DATA11) |       \
+               ATMEL_LCDC(PD, DATA12) | ATMEL_LCDC(PD, DATA16) |       \
+               ATMEL_LCDC(PD, DATA17) | ATMEL_LCDC(PD, DATA18) |       \
+               ATMEL_LCDC(PD, DATA19) | ATMEL_LCDC(PD, DATA20))
+
+#define ATMEL_LCDC_ALT_15B_DATA        (                                       \
+               ATMEL_LCDC(PE, DATA0)  | ATMEL_LCDC(PE, DATA1)  |       \
+               ATMEL_LCDC(PE, DATA2)  | ATMEL_LCDC(PE, DATA3)  |       \
+               ATMEL_LCDC(PE, DATA4)  | ATMEL_LCDC(PC, DATA5)  |       \
+               ATMEL_LCDC(PE, DATA8)  | ATMEL_LCDC(PE, DATA9)  |       \
+               ATMEL_LCDC(PE, DATA10) | ATMEL_LCDC(PE, DATA11) |       \
+               ATMEL_LCDC(PE, DATA12) | ATMEL_LCDC(PE, DATA16) |       \
+               ATMEL_LCDC(PE, DATA17) | ATMEL_LCDC(PE, DATA18) |       \
+               ATMEL_LCDC(PE, DATA19) | ATMEL_LCDC(PE, DATA20))
+
+#define ATMEL_LCDC_PRI_CONTROL (                                       \
+               ATMEL_LCDC(PC, CC)   | ATMEL_LCDC(PC, DVAL) |           \
+               ATMEL_LCDC(PC, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_ALT_CONTROL (                                       \
+               ATMEL_LCDC(PE, CC)   | ATMEL_LCDC(PE, DVAL) |           \
+               ATMEL_LCDC(PE, MODE) | ATMEL_LCDC(PC, PWR))
+
+#define ATMEL_LCDC_CONTROL (                                           \
+               ATMEL_LCDC(PC, HSYNC) | ATMEL_LCDC(PC, VSYNC) |         \
+               ATMEL_LCDC(PC, PCLK))
+
+#define ATMEL_LCDC_PRI_24BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_24B_DATA)
+
+#define ATMEL_LCDC_ALT_24BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_24B_DATA)
+
+#define ATMEL_LCDC_PRI_15BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_PRI_15B_DATA)
+
+#define ATMEL_LCDC_ALT_15BIT   (ATMEL_LCDC_CONTROL | ATMEL_LCDC_ALT_15B_DATA)
+
 #endif /* __ASM_ARCH_AT32AP700X_H__ */
index e60e9076544d08ace7891dbe1d1ffbf31df4f45f..c48386d66bc38f9fb0c1e287748b6de16a8ac903 100644 (file)
@@ -43,7 +43,7 @@ struct atmel_lcdfb_info;
 struct platform_device *
 at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
                     unsigned long fbmem_start, unsigned long fbmem_len,
-                    unsigned int pin_config);
+                    u64 pin_mask);
 
 struct usba_platform_data;
 struct platform_device *
index 4ec6abc68ea38084fae0a1d269f5fd53ebe34589..22ea79b740528b62dcd0bc9c4a211e2236bde564 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef __ASM_AVR32_ARCH_AT32AP_IO_H
 #define __ASM_AVR32_ARCH_AT32AP_IO_H
 
-/* For "bizarre" halfword swapping */
-#include <linux/byteorder/swabb.h>
+#include <linux/swab.h>
 
 #if defined(CONFIG_AP700X_32_BIT_SMC)
 # define __swizzle_addr_b(addr)        (addr ^ 3UL)
index b1abe6b4e4efef469f8098dd2d1ebb04873d937d..21c79373b53f04dae129e8a3907638f180577b7e 100644 (file)
 #define AT32_GPIOF_DEGLITCH    0x00000008      /* (IN) Filter glitches */
 #define AT32_GPIOF_MULTIDRV    0x00000010      /* Enable multidriver option */
 
-void at32_select_periph(unsigned int pin, unsigned int periph,
-                       unsigned long flags);
+void at32_select_periph(unsigned int port, unsigned int pin,
+                       unsigned int periph, unsigned long flags);
 void at32_select_gpio(unsigned int pin, unsigned long flags);
+void at32_deselect_pin(unsigned int pin);
 void at32_reserve_pin(unsigned int pin);
 
 #endif /* __ASM_ARCH_PORTMUX_H__ */
index 1040bda4fda7c843ea0d4955129f17cc94ab79bd..61ab15aae97008e798f5b89d6a225d195ca1b578 100644 (file)
@@ -35,7 +35,6 @@ static int __init pdc_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pdc_driver = {
-       .probe          = pdc_probe,
        .driver         = {
                .name   = "pdc",
        },
@@ -43,6 +42,6 @@ static struct platform_driver pdc_driver = {
 
 static int __init pdc_init(void)
 {
-       return platform_driver_register(&pdc_driver);
+       return platform_driver_probe(&pdc_driver, pdc_probe);
 }
 arch_initcall(pdc_init);
index 405ee6bad4ce59dd888448b100daba698cf12b0c..ed81a8bcb22d44ffa733beed2b43119caca29036 100644 (file)
@@ -50,35 +50,48 @@ static struct pio_device *gpio_to_pio(unsigned int gpio)
 }
 
 /* Pin multiplexing API */
+static DEFINE_SPINLOCK(pio_lock);
 
-void __init at32_select_periph(unsigned int pin, unsigned int periph,
-                              unsigned long flags)
+void __init at32_select_periph(unsigned int port, u32 pin_mask,
+                              unsigned int periph, unsigned long flags)
 {
        struct pio_device *pio;
-       unsigned int pin_index = pin & 0x1f;
-       u32 mask = 1 << pin_index;
 
-       pio = gpio_to_pio(pin);
+       /* assign and verify pio */
+       pio = gpio_to_pio(port);
        if (unlikely(!pio)) {
-               printk("pio: invalid pin %u\n", pin);
+               printk(KERN_WARNING "pio: invalid port %u\n", port);
                goto fail;
        }
 
-       if (unlikely(test_and_set_bit(pin_index, &pio->pinmux_mask)
-                        || gpiochip_is_requested(&pio->chip, pin_index))) {
-               printk("%s: pin %u is busy\n", pio->name, pin_index);
+       /* Test if any of the requested pins is already muxed */
+       spin_lock(&pio_lock);
+       if (unlikely(pio->pinmux_mask & pin_mask)) {
+               printk(KERN_WARNING "%s: pin(s) busy (requested 0x%x, busy 0x%x)\n",
+                      pio->name, pin_mask, pio->pinmux_mask & pin_mask);
+               spin_unlock(&pio_lock);
                goto fail;
        }
 
-       pio_writel(pio, PUER, mask);
+       pio->pinmux_mask |= pin_mask;
+
+       /* enable pull ups */
+       pio_writel(pio, PUER, pin_mask);
+
+       /* select either peripheral A or B */
        if (periph)
-               pio_writel(pio, BSR, mask);
+               pio_writel(pio, BSR, pin_mask);
        else
-               pio_writel(pio, ASR, mask);
+               pio_writel(pio, ASR, pin_mask);
+
+       /* enable peripheral control */
+       pio_writel(pio, PDR, pin_mask);
 
-       pio_writel(pio, PDR, mask);
+       /* Disable pull ups if not requested. */
        if (!(flags & AT32_GPIOF_PULLUP))
-               pio_writel(pio, PUDR, mask);
+               pio_writel(pio, PUDR, pin_mask);
+
+       spin_unlock(&pio_lock);
 
        return;
 
@@ -134,6 +147,25 @@ fail:
        dump_stack();
 }
 
+/*
+ * Undo a previous pin reservation. Will not affect the hardware
+ * configuration.
+ */
+void at32_deselect_pin(unsigned int pin)
+{
+       struct pio_device *pio;
+       unsigned int pin_index = pin & 0x1f;
+
+       pio = gpio_to_pio(pin);
+       if (unlikely(!pio)) {
+               printk("pio: invalid pin %u\n", pin);
+               dump_stack();
+               return;
+       }
+
+       clear_bit(pin_index, &pio->pinmux_mask);
+}
+
 /* Reserve a pin, preventing anyone else from changing its configuration. */
 void __init at32_reserve_pin(unsigned int pin)
 {
@@ -382,7 +414,6 @@ static int __init pio_probe(struct platform_device *pdev)
 }
 
 static struct platform_driver pio_driver = {
-       .probe          = pio_probe,
        .driver         = {
                .name           = "pio",
        },
@@ -390,7 +421,7 @@ static struct platform_driver pio_driver = {
 
 static int __init pio_init(void)
 {
-       return platform_driver_register(&pio_driver);
+       return platform_driver_probe(&pio_driver, pio_probe);
 }
 postcore_initcall(pio_init);
 
index 1fe81c3c1e86921cedd64597ce3f3fb515007f0b..e0eb520e02872e01cec8fdb69c61439c27cc13fc 100644 (file)
@@ -5,4 +5,4 @@ oprofile-y              := $(addprefix ../../../drivers/oprofile/,      \
                                event_buffer.o oprofile_files.o         \
                                oprofilefs.o oprofile_stats.o           \
                                timer_int.o)
-oprofile-y             += op_model_avr32.o
+oprofile-y             += op_model_avr32.o backtrace.o
diff --git a/arch/avr32/oprofile/backtrace.c b/arch/avr32/oprofile/backtrace.c
new file mode 100644 (file)
index 0000000..75d9ad6
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * AVR32 specific backtracing code for oprofile
+ *
+ * Copyright 2008 Weinmann GmbH
+ *
+ * Author: Nikolaus Voss <n.voss@weinmann.de>
+ *
+ * Based on i386 oprofile backtrace code by John Levon and David Smith
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+
+/* The first two words of each frame on the stack look like this if we have
+ * frame pointers */
+struct frame_head {
+       unsigned long lr;
+       struct frame_head *fp;
+};
+
+/* copied from arch/avr32/kernel/process.c */
+static inline int valid_stack_ptr(struct thread_info *tinfo, unsigned long p)
+{
+       return (p > (unsigned long)tinfo)
+               && (p < (unsigned long)tinfo + THREAD_SIZE - 3);
+}
+
+/* copied from arch/x86/oprofile/backtrace.c */
+static struct frame_head *dump_user_backtrace(struct frame_head *head)
+{
+       struct frame_head bufhead[2];
+
+       /* Also check accessibility of one struct frame_head beyond */
+       if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+               return NULL;
+       if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+               return NULL;
+
+       oprofile_add_trace(bufhead[0].lr);
+
+       /* frame pointers should strictly progress back up the stack
+        * (towards higher addresses) */
+       if (bufhead[0].fp <= head)
+               return NULL;
+
+       return bufhead[0].fp;
+}
+
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+       /* Get first frame pointer */
+       struct frame_head *head = (struct frame_head *)(regs->r7);
+
+       if (!user_mode(regs)) {
+#ifdef CONFIG_FRAME_POINTER
+               /*
+                * Traverse the kernel stack from frame to frame up to
+                * "depth" steps.
+                */
+               while (depth-- && valid_stack_ptr(task_thread_info(current),
+                                                 (unsigned long)head)) {
+                       oprofile_add_trace(head->lr);
+                       if (head->fp <= head)
+                               break;
+                       head = head->fp;
+               }
+#endif
+       } else {
+               /* Assume we have frame pointers in user mode process */
+               while (depth-- && head)
+                       head = dump_user_backtrace(head);
+       }
+}
+
+
index df42325c7f81da49e882c23c535a8eafd7a2356c..a3e9b3c4845a50f0fc53bf164923a084650f5c17 100644 (file)
@@ -22,6 +22,8 @@
 #define AVR32_PERFCTR_IRQ_GROUP        0
 #define AVR32_PERFCTR_IRQ_LINE 1
 
+void avr32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 enum { PCCNT, PCNT0, PCNT1, NR_counter };
 
 struct avr32_perf_counter {
@@ -223,6 +225,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        memcpy(ops, &avr32_perf_counter_ops,
                        sizeof(struct oprofile_operations));
 
+       ops->backtrace = avr32_backtrace;
+
        printk(KERN_INFO "oprofile: using AVR32 performance monitoring.\n");
 
        return 0;
index 9294e4b0c8bc395fb17b525c132ebd593053ef70..118d4297900319df2d97840fc7149cce0ad8610c 100644 (file)
@@ -113,11 +113,6 @@ typedef struct siginfo {
 #undef NSIGSEGV
 #define NSIGSEGV       3
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index 12f1bce037be7f57c422b26246b692838b4fbc9d..49495b0534edaf8499ab4e614dffef7819850dec 100644 (file)
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index a214002114ed90b0f8924c6837cbfcc622af737c..97671dac12a649765e3b8fda6d22317963872749 100644 (file)
@@ -20,6 +20,11 @@ config GENERIC_ISA_DMA
        bool
        default y
 
+config GENERIC_GPIO
+       bool
+       help
+         Generic GPIO API support
+
 config ARCH_NO_VIRT_TO_BUS
        def_bool y
 
@@ -69,6 +74,9 @@ config SPARC
        select HAVE_OPROFILE
        select HAVE_ARCH_KGDB if !SMP
        select HAVE_ARCH_TRACEHOOK
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select RTC_CLASS
+       select RTC_DRV_M48T59
 
 # Identify this as a Sparc32 build
 config SPARC32
@@ -204,17 +212,6 @@ config SUN_PM
          Enable power management and CPU standby features on supported
          SPARC platforms.
 
-config SUN4
-       bool "Support for SUN4 machines (disables SUN4[CDM] support)"
-       depends on !SMP
-       default n
-       help
-         Say Y here if, and only if, your machine is a sun4. Note that
-         a kernel compiled with this option will run only on sun4.
-         (And the current version will probably work only on sun4/330.)
-
-if !SUN4
-
 config PCI
        bool "Support for PCI and PS/2 keyboard/mouse"
        help
@@ -227,11 +224,6 @@ config PCI_SYSCALL
 
 source "drivers/pci/Kconfig"
 
-endif
-
-config NO_DMA
-       def_bool !PCI
-
 config SUN_OPENPROMFS
        tristate "Openprom tree appears in /proc/openprom"
        help
@@ -263,9 +255,7 @@ source "net/Kconfig"
 
 source "drivers/Kconfig"
 
-if !SUN4
 source "drivers/sbus/char/Kconfig"
-endif
 
 # This one must be before the filesystem configs. -DaveM
 
index a5f0ce734ff7dab790fe2df8e0c1915e2327c6f3..2ba7183bc1f05572fba2636ce160a5c43400963e 100644 (file)
@@ -22,7 +22,6 @@ header-y += unistd_64.h
 
 header-y += apc.h
 header-y += asi.h
-header-y += bpp.h
 header-y += display7seg.h
 header-y += envctrl.h
 header-y += fbio.h
@@ -41,5 +40,4 @@ header-y += reg_64.h
 header-y += traps.h
 header-y += uctx.h
 header-y += utrap.h
-header-y += vfc_ioctls.h
 header-y += watchdog.h
index a619a4d97aaee4b69469bc97159196ee60846089..a995bf8aba3fa0e680b6223de217466bbc49fbe1 100644 (file)
 /* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+
    likes byte accesses. These are to avoid ifdef mania. */
 
-#ifdef CONFIG_SUN4
-#define lduXa  lduha
-#define stXa   stha
-#else
 #define lduXa  lduba
 #define stXa   stba
-#endif
 
 #endif /* !(_SPARC_ASMMACRO_H) */
diff --git a/arch/sparc/include/asm/bpp.h b/arch/sparc/include/asm/bpp.h
deleted file mode 100644 (file)
index 31f515e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _SPARC_BPP_H
-#define _SPARC_BPP_H
-
-/*
- * Copyright (c) 1995 Picture Elements
- *     Stephen Williams
- *     Gus Baldauf
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-#include  <linux/ioctl.h>
-
-/*
- * This is a driver that supports IEEE Std 1284-1994 communications
- * with compliant or compatible devices. It will use whatever features
- * the device supports, prefering those that are typically faster.
- *
- * When the device is opened, it is left in COMPATIBILITY mode, and
- * writes work like any printer device. The driver only attempt to
- * negotiate 1284 modes when needed so that plugs can be pulled,
- * switch boxes switched, etc., without disrupting things. It will
- * also leave the device in compatibility mode when closed.
- */
-
-
-
-/*
- * This driver also supplies ioctls to manually manipulate the
- * pins. This is great for testing devices, or writing code to deal
- * with bizzarro-mode of the ACME Special TurboThingy Plus.
- *
- * NOTE: These ioctl currently do not interact well with
- * read/write. Caveat emptor.
- *
- * PUT_PINS allows us to assign the sense of all the pins, including
- * the data pins if being driven by the host. The GET_PINS returns the
- * pins that the peripheral drives, including data if appropriate.
- */
-
-# define BPP_PUT_PINS _IOW('B', 1, int)
-# define BPP_GET_PINS _IOR('B', 2, char) /* that's bogus - should've been _IO */
-# define BPP_PUT_DATA _IOW('B', 3, int)
-# define BPP_GET_DATA _IOR('B', 4, char) /* ditto */
-
-/*
- * Set the data bus to input mode. Disengage the data bin driver and
- * be prepared to read values from the peripheral. If the arg is 0,
- * then revert the bus to output mode.
- */
-# define BPP_SET_INPUT _IOW('B', 5, int)
-
-/*
- * These bits apply to the PUT operation...
- */
-# define BPP_PP_nStrobe   0x0001
-# define BPP_PP_nAutoFd   0x0002
-# define BPP_PP_nInit     0x0004
-# define BPP_PP_nSelectIn 0x0008
-
-/*
- * These apply to the GET operation, which also reads the current value
- * of the previously put values. A bit mask of these will be returned
- * as a bit mask in the return code of the ioctl().
- */
-# define BPP_GP_nAck   0x0100
-# define BPP_GP_Busy   0x0200
-# define BPP_GP_PError 0x0400
-# define BPP_GP_Select 0x0800
-# define BPP_GP_nFault 0x1000
-
-#endif
index e179bc12f64a478ff9d3eaba6bf337f1a27b1539..61d86bbbe2b2f5270043d9a3ee72330119f65eb0 100644 (file)
@@ -7,10 +7,6 @@
 #include <asm/cpudata.h>
 #endif
 
-#ifdef CONFIG_SPARC64
-#include <asm/sstate.h>
-#endif
-
 extern unsigned long loops_per_jiffy;
 
 static void __init check_bugs(void)
@@ -18,7 +14,4 @@ static void __init check_bugs(void)
 #if defined(CONFIG_SPARC32) && !defined(CONFIG_SMP)
        cpu_data(0).udelay_val = loops_per_jiffy;
 #endif
-#ifdef CONFIG_SPARC64
-       sstate_running();
-#endif
 }
index 532975ecfe10c1b6720f48bf177632901f8cdb94..7da7c13d23c4f10af35b4aa159976f9dfa277808 100644 (file)
@@ -86,7 +86,6 @@ extern struct trap_per_cpu trap_block[NR_CPUS];
 extern void init_cur_cpu_trap(struct thread_info *);
 extern void setup_tba(void);
 extern int ncpus_probed;
-extern void __init cpu_probe(void);
 extern const struct seq_operations cpuinfo_op;
 
 extern unsigned long real_hard_smp_processor_id(void);
index f3a641e6b2c88645cc09852923d1804bba410546..8a57ea0573e6a29205ea9bdc97250f5c0955171f 100644 (file)
@@ -1,11 +1,60 @@
 #ifndef _ASM_SPARC_DMA_MAPPING_H
 #define _ASM_SPARC_DMA_MAPPING_H
 
+#include <linux/types.h>
 
-#ifdef CONFIG_PCI
-#include <asm-generic/dma-mapping.h>
-#else
-#include <asm-generic/dma-mapping-broken.h>
-#endif /* PCI */
+struct device;
+struct scatterlist;
+struct page;
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+extern void *dma_alloc_coherent(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_free_coherent(struct device *dev, size_t size,
+                             void *cpu_addr, dma_addr_t dma_handle);
+extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                                size_t size,
+                                enum dma_data_direction direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                            size_t size,
+                            enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                              unsigned long offset, size_t size,
+                              enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                          size_t size, enum dma_data_direction direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                     int nents, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                        int nents, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                   size_t size,
+                                   enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+                                      dma_addr_t dma_handle,
+                                      size_t size,
+                                      enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+                                         dma_addr_t dma_handle,
+                                         unsigned long offset,
+                                         size_t size,
+                                         enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+                                            dma_addr_t dma_handle,
+                                            unsigned long offset, size_t size,
+                                            enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                               int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev,
+                                  struct scatterlist *sg, int nelems,
+                                  enum dma_data_direction direction);
+extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
+extern int dma_get_cache_alignment(void);
+
+#define dma_alloc_noncoherent  dma_alloc_coherent
+#define dma_free_noncoherent   dma_free_coherent
 
 #endif /* _ASM_SPARC_DMA_MAPPING_H */
index aa1d90ac04c58b2db3c907ab8e5555aa7ae90b75..b554927bbaf668102be8950d25fac53bca79f954 100644 (file)
@@ -1,8 +1,139 @@
-#ifndef ___ASM_SPARC_DMA_H
-#define ___ASM_SPARC_DMA_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma_64.h>
+#ifndef _ASM_SPARC_DMA_H
+#define _ASM_SPARC_DMA_H
+
+/* These are irrelevant for Sparc DMA, but we leave it in so that
+ * things can compile.
+ */
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ    1
+#define DMA_MODE_WRITE   2
+#define MAX_DMA_ADDRESS  (~0UL)
+
+/* Useful constants */
+#define SIZE_16MB      (16*1024*1024)
+#define SIZE_64K       (64*1024)
+
+/* SBUS DMA controller reg offsets */
+#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
+#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
+#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
+#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
+
+/* Fields in the cond_reg register */
+/* First, the version identification bits */
+#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
+#define DMA_VERS0        0x00000000        /* Sunray DMA version */
+#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
+#define DMA_VERS1        0x80000000        /* DMA rev 1 */
+#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
+#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
+#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
+
+#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
+#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
+#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
+#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
+#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
+#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
+#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
+#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
+#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
+#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
+#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
+#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
+#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
+#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
+#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
+#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
+#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
+#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
+#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
+#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
+#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
+#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
+#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
+#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
+#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
+#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
+#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
+#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
+#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
+#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
+#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
+#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
+#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
+#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
+#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
+#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
+#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
+#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
+#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
+#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
+#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
+
+/* Values describing the burst-size property from the PROM */
+#define DMA_BURST1       0x01
+#define DMA_BURST2       0x02
+#define DMA_BURST4       0x04
+#define DMA_BURST8       0x08
+#define DMA_BURST16      0x10
+#define DMA_BURST32      0x20
+#define DMA_BURST64      0x40
+#define DMA_BURSTBITS    0x7f
+
+/* From PCI */
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
 #else
-#include <asm/dma_32.h>
+#define isa_dma_bridge_buggy   (0)
 #endif
+
+#ifdef CONFIG_SPARC32
+
+/* Routines for data transfer buffers. */
+BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
+BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
+
+#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
+#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
+
+struct page;
+struct device;
+struct scatterlist;
+
+/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
+BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct device *, struct scatterlist *, int)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, struct device *, __u32, unsigned long)
+BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct device *, struct scatterlist *, int)
+
+#define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len)
+#define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz)
+#define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len)
+#define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz)
+
+/*
+ * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
+ *
+ * The mmu_map_dma_area establishes two mappings in one go.
+ * These mappings point to pages normally mapped at 'va' (linear address).
+ * First mapping is for CPU visible address at 'a', uncached.
+ * This is an alias, but it works because it is an uncached mapping.
+ * Second mapping is for device visible address, or "bus" address.
+ * The bus address is returned at '*pba'.
+ *
+ * These functions seem distinct, but are hard to split. On sun4c,
+ * at least for now, 'a' is equal to bus address, and retured in *pba.
+ * On sun4m, page attributes depend on the CPU type, so we have to
+ * know if we are mapping RAM or I/O, so it has to be an additional argument
+ * to a separate mapping function for CPU visible mappings.
+ */
+BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len)
+BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len)
+
+#define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len)
+#define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len)
 #endif
+
+#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_32.h b/arch/sparc/include/asm/dma_32.h
deleted file mode 100644 (file)
index cf7189c..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/* include/asm/dma.h
- *
- * Copyright 1995 (C) David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _ASM_SPARC_DMA_H
-#define _ASM_SPARC_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-
-#include <asm/vac-ops.h>  /* for invalidate's, etc. */
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/spinlock.h>
-
-struct page;
-extern spinlock_t  dma_spin_lock;
-
-static inline unsigned long claim_dma_lock(void)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dma_spin_lock, flags);
-       return flags;
-}
-
-static inline void release_dma_lock(unsigned long flags)
-{
-       spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define MAX_DMA_ADDRESS  (~0UL)
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
-#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
-#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-       dvmarev0,
-       dvmaesc1,
-       dvmarev1,
-       dvmarev2,
-       dvmarev3,
-       dvmarevplus,
-       dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-       struct sbus_dma *next;
-       struct sbus_dev *sdev;
-       void __iomem *regs;
-
-       /* Status, misc info */
-       int node;                /* Prom node for this DMA device */
-       int running;             /* Are we doing DMA now? */
-       int allocated;           /* Are we "owned" by anyone yet? */
-
-       /* Transfer information. */
-       unsigned long addr;      /* Start address of current transfer */
-       int nbytes;              /* Size of current transfer */
-       int realbytes;           /* For splitting up large transfers, etc. */
-
-       /* DMA revision */
-       enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#ifdef CONFIG_SUN4
-/* Have to sort this out. Does rev0 work fine on sun4[cmd] without isbroken?
- * Or is rev0 present only on sun4 boxes? -jj */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev0 || (dma)->revision == dvmarev1)
-#else
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#endif
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_RST_BPP      DMA_RST_SCSI      /* Reset the BPP controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x00080000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI/BPP: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI/BPP: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_BPP_ON       DMA_SCSI_ON       /* Enable BPP dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((((regs)->cond_reg) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((((regs)->cond_reg) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)))
-#define DMA_WRITE_P(regs)  ((((regs)->cond_reg) & DMA_ST_WRITE))
-#define DMA_OFF(regs)      ((((regs)->cond_reg) &= (~DMA_ENABLE)))
-#define DMA_INTSOFF(regs)  ((((regs)->cond_reg) &= (~DMA_INT_ENAB)))
-#define DMA_INTSON(regs)   ((((regs)->cond_reg) |= (DMA_INT_ENAB)))
-#define DMA_PUNTFIFO(regs) ((((regs)->cond_reg) |= DMA_FIFO_INV))
-#define DMA_SETSTART(regs, addr)  ((((regs)->st_addr) = (char *) addr))
-#define DMA_BEGINDMA_W(regs) \
-        ((((regs)->cond_reg |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB))))
-#define DMA_BEGINDMA_R(regs) \
-        ((((regs)->cond_reg |= ((DMA_ENABLE|DMA_INT_ENAB)&(~DMA_ST_WRITE)))))
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-       if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#if 0  /* P3 this stuff is inline in ledma.c:init_restart_ledma() */
-/* Pause until counter runs out or BIT isn't set in the DMA condition
- * register.
- */
-static inline void sparc_dma_pause(struct sparc_dma_registers *regs,
-                                      unsigned long bit)
-{
-       int ctr = 50000;   /* Let's find some bugs ;) */
-
-       /* Busy wait until the bit is not set any more */
-       while((regs->cond_reg&bit) && (ctr>0)) {
-               ctr--;
-               __delay(5);
-       }
-
-       /* Check for bogus outcome. */
-       if(!ctr)
-               panic("DMA timeout");
-}
-
-/* Reset the friggin' thing... */
-#define DMA_RESET(dma) do { \
-       struct sparc_dma_registers *regs = dma->regs;                      \
-       /* Let the current FIFO drain itself */                            \
-       sparc_dma_pause(regs, (DMA_FIFO_ISDRAIN));                         \
-       /* Reset the logic */                                              \
-       regs->cond_reg |= (DMA_RST_SCSI);     /* assert */                 \
-       __delay(400);                         /* let the bits set ;) */    \
-       regs->cond_reg &= ~(DMA_RST_SCSI);    /* de-assert */              \
-       sparc_dma_enable_interrupts(regs);    /* Re-enable interrupts */   \
-       /* Enable FAST transfers if available */                           \
-       if(dma->revision>dvmarev1) regs->cond_reg |= DMA_3CLKS;            \
-       dma->running = 0;                                                  \
-} while(0)
-#endif
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-extern int get_dma_list(char *);
-extern int request_dma(unsigned int, __const__ char *);
-extern void free_dma(unsigned int);
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy   (0)
-#endif
-
-/* Routines for data transfer buffers. */
-BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long)
-BTFIXUPDEF_CALL(void,   mmu_unlockarea, char *, unsigned long)
-
-#define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len)
-#define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len)
-
-/* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */
-BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, char *, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_get_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_one, __u32, unsigned long, struct sbus_bus *sbus)
-BTFIXUPDEF_CALL(void,  mmu_release_scsi_sgl, struct scatterlist *, int, struct sbus_bus *sbus)
-
-#define mmu_get_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_get_scsi_one)(vaddr,len,sbus)
-#define mmu_get_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_get_scsi_sgl)(sg,sz,sbus)
-#define mmu_release_scsi_one(vaddr,len,sbus) BTFIXUP_CALL(mmu_release_scsi_one)(vaddr,len,sbus)
-#define mmu_release_scsi_sgl(sg,sz,sbus) BTFIXUP_CALL(mmu_release_scsi_sgl)(sg,sz,sbus)
-
-/*
- * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep.
- *
- * The mmu_map_dma_area establishes two mappings in one go.
- * These mappings point to pages normally mapped at 'va' (linear address).
- * First mapping is for CPU visible address at 'a', uncached.
- * This is an alias, but it works because it is an uncached mapping.
- * Second mapping is for device visible address, or "bus" address.
- * The bus address is returned at '*pba'.
- *
- * These functions seem distinct, but are hard to split. On sun4c,
- * at least for now, 'a' is equal to bus address, and retured in *pba.
- * On sun4m, page attributes depend on the CPU type, so we have to
- * know if we are mapping RAM or I/O, so it has to be an additional argument
- * to a separate mapping function for CPU visible mappings.
- */
-BTFIXUPDEF_CALL(int,  mmu_map_dma_area, dma_addr_t *, unsigned long, unsigned long, int len)
-BTFIXUPDEF_CALL(struct page *, mmu_translate_dvma, unsigned long busa)
-BTFIXUPDEF_CALL(void,  mmu_unmap_dma_area, unsigned long busa, int len)
-
-#define mmu_map_dma_area(pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(pba,va,a,len)
-#define mmu_unmap_dma_area(ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(ba,len)
-#define mmu_translate_dvma(ba)     BTFIXUP_CALL(mmu_translate_dvma)(ba)
-
-#endif /* !(_ASM_SPARC_DMA_H) */
diff --git a/arch/sparc/include/asm/dma_64.h b/arch/sparc/include/asm/dma_64.h
deleted file mode 100644 (file)
index 46a8aec..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * include/asm/dma.h
- *
- * Copyright 1996 (C) David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _ASM_SPARC64_DMA_H
-#define _ASM_SPARC64_DMA_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-
-#include <asm/sbus.h>
-#include <asm/delay.h>
-#include <asm/oplib.h>
-
-/* These are irrelevant for Sparc DMA, but we leave it in so that
- * things can compile.
- */
-#define MAX_DMA_CHANNELS 8
-#define DMA_MODE_READ    1
-#define DMA_MODE_WRITE   2
-#define MAX_DMA_ADDRESS  (~0UL)
-
-/* Useful constants */
-#define SIZE_16MB      (16*1024*1024)
-#define SIZE_64K       (64*1024)
-
-/* SBUS DMA controller reg offsets */
-#define DMA_CSR                0x00UL          /* rw  DMA control/status register    0x00   */
-#define DMA_ADDR       0x04UL          /* rw  DMA transfer address register  0x04   */
-#define DMA_COUNT      0x08UL          /* rw  DMA transfer count register    0x08   */
-#define DMA_TEST       0x0cUL          /* rw  DMA test/debug register        0x0c   */
-
-/* DVMA chip revisions */
-enum dvma_rev {
-       dvmarev0,
-       dvmaesc1,
-       dvmarev1,
-       dvmarev2,
-       dvmarev3,
-       dvmarevplus,
-       dvmahme
-};
-
-#define DMA_HASCOUNT(rev)  ((rev)==dvmaesc1)
-
-/* Linux DMA information structure, filled during probe. */
-struct sbus_dma {
-       struct sbus_dma *next;
-       struct sbus_dev *sdev;
-       void __iomem *regs;
-
-       /* Status, misc info */
-       int node;                /* Prom node for this DMA device */
-       int running;             /* Are we doing DMA now? */
-       int allocated;           /* Are we "owned" by anyone yet? */
-
-       /* Transfer information. */
-       u32 addr;                /* Start address of current transfer */
-       int nbytes;              /* Size of current transfer */
-       int realbytes;           /* For splitting up large transfers, etc. */
-
-       /* DMA revision */
-       enum dvma_rev revision;
-};
-
-extern struct sbus_dma *dma_chain;
-
-/* Broken hardware... */
-#define DMA_ISBROKEN(dma)    ((dma)->revision == dvmarev1)
-#define DMA_ISESC1(dma)      ((dma)->revision == dvmaesc1)
-
-/* Main routines in dma.c */
-extern void dvma_init(struct sbus_bus *);
-
-/* Fields in the cond_reg register */
-/* First, the version identification bits */
-#define DMA_DEVICE_ID    0xf0000000        /* Device identification bits */
-#define DMA_VERS0        0x00000000        /* Sunray DMA version */
-#define DMA_ESCV1        0x40000000        /* DMA ESC Version 1 */
-#define DMA_VERS1        0x80000000        /* DMA rev 1 */
-#define DMA_VERS2        0xa0000000        /* DMA rev 2 */
-#define DMA_VERHME       0xb0000000        /* DMA hme gate array */
-#define DMA_VERSPLUS     0x90000000        /* DMA rev 1 PLUS */
-
-#define DMA_HNDL_INTR    0x00000001        /* An IRQ needs to be handled */
-#define DMA_HNDL_ERROR   0x00000002        /* We need to take an error */
-#define DMA_FIFO_ISDRAIN 0x0000000c        /* The DMA FIFO is draining */
-#define DMA_INT_ENAB     0x00000010        /* Turn on interrupts */
-#define DMA_FIFO_INV     0x00000020        /* Invalidate the FIFO */
-#define DMA_ACC_SZ_ERR   0x00000040        /* The access size was bad */
-#define DMA_FIFO_STDRAIN 0x00000040        /* DMA_VERS1 Drain the FIFO */
-#define DMA_RST_SCSI     0x00000080        /* Reset the SCSI controller */
-#define DMA_RST_ENET     DMA_RST_SCSI      /* Reset the ENET controller */
-#define DMA_ST_WRITE     0x00000100        /* write from device to memory */
-#define DMA_ENABLE       0x00000200        /* Fire up DMA, handle requests */
-#define DMA_PEND_READ    0x00000400        /* DMA_VERS1/0/PLUS Pending Read */
-#define DMA_ESC_BURST    0x00000800        /* 1=16byte 0=32byte */
-#define DMA_READ_AHEAD   0x00001800        /* DMA read ahead partial longword */
-#define DMA_DSBL_RD_DRN  0x00001000        /* No EC drain on slave reads */
-#define DMA_BCNT_ENAB    0x00002000        /* If on, use the byte counter */
-#define DMA_TERM_CNTR    0x00004000        /* Terminal counter */
-#define DMA_SCSI_SBUS64  0x00008000        /* HME: Enable 64-bit SBUS mode. */
-#define DMA_CSR_DISAB    0x00010000        /* No FIFO drains during csr */
-#define DMA_SCSI_DISAB   0x00020000        /* No FIFO drains during reg */
-#define DMA_DSBL_WR_INV  0x00020000        /* No EC inval. on slave writes */
-#define DMA_ADD_ENABLE   0x00040000        /* Special ESC DVMA optimization */
-#define DMA_E_BURSTS    0x000c0000        /* ENET: SBUS r/w burst mask */
-#define DMA_E_BURST32   0x00040000        /* ENET: SBUS 32 byte r/w burst */
-#define DMA_E_BURST16   0x00000000        /* ENET: SBUS 16 byte r/w burst */
-#define DMA_BRST_SZ      0x000c0000        /* SCSI: SBUS r/w burst size */
-#define DMA_BRST64       0x000c0000        /* SCSI: 64byte bursts (HME on UltraSparc only) */
-#define DMA_BRST32       0x00040000        /* SCSI: 32byte bursts */
-#define DMA_BRST16       0x00000000        /* SCSI: 16byte bursts */
-#define DMA_BRST0        0x00080000        /* SCSI: no bursts (non-HME gate arrays) */
-#define DMA_ADDR_DISAB   0x00100000        /* No FIFO drains during addr */
-#define DMA_2CLKS        0x00200000        /* Each transfer = 2 clock ticks */
-#define DMA_3CLKS        0x00400000        /* Each transfer = 3 clock ticks */
-#define DMA_EN_ENETAUI   DMA_3CLKS         /* Put lance into AUI-cable mode */
-#define DMA_CNTR_DISAB   0x00800000        /* No IRQ when DMA_TERM_CNTR set */
-#define DMA_AUTO_NADDR   0x01000000        /* Use "auto nxt addr" feature */
-#define DMA_SCSI_ON      0x02000000        /* Enable SCSI dma */
-#define DMA_PARITY_OFF   0x02000000        /* HME: disable parity checking */
-#define DMA_LOADED_ADDR  0x04000000        /* Address has been loaded */
-#define DMA_LOADED_NADDR 0x08000000        /* Next address has been loaded */
-#define DMA_RESET_FAS366 0x08000000        /* HME: Assert RESET to FAS366 */
-
-/* Values describing the burst-size property from the PROM */
-#define DMA_BURST1       0x01
-#define DMA_BURST2       0x02
-#define DMA_BURST4       0x04
-#define DMA_BURST8       0x08
-#define DMA_BURST16      0x10
-#define DMA_BURST32      0x20
-#define DMA_BURST64      0x40
-#define DMA_BURSTBITS    0x7f
-
-/* Determine highest possible final transfer address given a base */
-#define DMA_MAXEND(addr) (0x01000000UL-(((unsigned long)(addr))&0x00ffffffUL))
-
-/* Yes, I hack a lot of elisp in my spare time... */
-#define DMA_ERROR_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_HNDL_ERROR))
-#define DMA_IRQ_P(regs)    ((sbus_readl((regs) + DMA_CSR)) & (DMA_HNDL_INTR | DMA_HNDL_ERROR))
-#define DMA_WRITE_P(regs)  ((sbus_readl((regs) + DMA_CSR) & DMA_ST_WRITE))
-#define DMA_OFF(__regs)                \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp &= ~DMA_ENABLE; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSOFF(__regs)    \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp &= ~DMA_INT_ENAB; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_INTSON(__regs)     \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= DMA_INT_ENAB; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_PUNTFIFO(__regs)   \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= DMA_FIFO_INV; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_SETSTART(__regs, __addr)   \
-       sbus_writel((u32)(__addr), (__regs) + DMA_ADDR);
-#define DMA_BEGINDMA_W(__regs) \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= (DMA_ST_WRITE|DMA_ENABLE|DMA_INT_ENAB); \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-#define DMA_BEGINDMA_R(__regs) \
-do {   u32 tmp = sbus_readl((__regs) + DMA_CSR); \
-       tmp |= (DMA_ENABLE|DMA_INT_ENAB); \
-       tmp &= ~DMA_ST_WRITE; \
-       sbus_writel(tmp, (__regs) + DMA_CSR); \
-} while(0)
-
-/* For certain DMA chips, we need to disable ints upon irq entry
- * and turn them back on when we are done.  So in any ESP interrupt
- * handler you *must* call DMA_IRQ_ENTRY upon entry and DMA_IRQ_EXIT
- * when leaving the handler.  You have been warned...
- */
-#define DMA_IRQ_ENTRY(dma, dregs) do { \
-        if(DMA_ISBROKEN(dma)) DMA_INTSOFF(dregs); \
-   } while (0)
-
-#define DMA_IRQ_EXIT(dma, dregs) do { \
-       if(DMA_ISBROKEN(dma)) DMA_INTSON(dregs); \
-   } while(0)
-
-#define for_each_dvma(dma) \
-        for((dma) = dma_chain; (dma); (dma) = (dma)->next)
-
-/* From PCI */
-
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
-#define isa_dma_bridge_buggy   (0)
-#endif
-
-#endif /* !(_ASM_SPARC64_DMA_H) */
diff --git a/arch/sparc/include/asm/ebus.h b/arch/sparc/include/asm/ebus.h
deleted file mode 100644 (file)
index 83a6d16..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_EBUS_H
-#define ___ASM_SPARC_EBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/ebus_64.h>
-#else
-#include <asm/ebus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/ebus_32.h b/arch/sparc/include/asm/ebus_32.h
deleted file mode 100644 (file)
index f91f0b2..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- */
-
-#ifndef __SPARC_EBUS_H
-#define __SPARC_EBUS_H
-
-#ifndef _LINUX_IOPORT_H
-#include <linux/ioport.h>
-#endif
-#include <linux/of_device.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-       struct linux_ebus_child         *next;
-       struct linux_ebus_device        *parent;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-
-struct linux_ebus_device {
-       struct of_device                ofdev;
-       struct linux_ebus_device        *next;
-       struct linux_ebus_child         *children;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-       struct of_device                ofdev;
-       struct linux_ebus               *next;
-       struct linux_ebus_device        *devices;
-       struct linux_pbm_info           *parent;
-       struct pci_dev                  *self;
-       struct device_node              *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct linux_ebus_dma {
-       unsigned int dcsr;
-       unsigned int dacr;
-       unsigned int dbcr;
-};
-
-#define EBUS_DCSR_INT_PEND     0x00000001
-#define EBUS_DCSR_ERR_PEND     0x00000002
-#define EBUS_DCSR_DRAIN                0x00000004
-#define EBUS_DCSR_INT_EN       0x00000010
-#define EBUS_DCSR_RESET                0x00000080
-#define EBUS_DCSR_WRITE                0x00000100
-#define EBUS_DCSR_EN_DMA       0x00000200
-#define EBUS_DCSR_CYC_PEND     0x00000400
-#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
-#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
-#define EBUS_DCSR_EN_CNT       0x00002000
-#define EBUS_DCSR_TC           0x00004000
-#define EBUS_DCSR_DIS_CSR_DRN  0x00010000
-#define EBUS_DCSR_BURST_SZ_MASK        0x000c0000
-#define EBUS_DCSR_BURST_SZ_1   0x00080000
-#define EBUS_DCSR_BURST_SZ_4   0x00000000
-#define EBUS_DCSR_BURST_SZ_8   0x00040000
-#define EBUS_DCSR_BURST_SZ_16  0x000c0000
-#define EBUS_DCSR_DIAG_EN      0x00100000
-#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
-#define EBUS_DCSR_TCI_DIS      0x00800000
-#define EBUS_DCSR_EN_NEXT      0x01000000
-#define EBUS_DCSR_DMA_ON       0x02000000
-#define EBUS_DCSR_A_LOADED     0x04000000
-#define EBUS_DCSR_NA_LOADED    0x08000000
-#define EBUS_DCSR_DEV_ID_MASK  0xf0000000
-
-extern struct linux_ebus               *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)                                             \
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)                                     \
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)                                 \
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_64.h b/arch/sparc/include/asm/ebus_64.h
deleted file mode 100644 (file)
index 14c6a11..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * ebus.h: PCI to Ebus pseudo driver software state.
- *
- * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
- */
-
-#ifndef __SPARC64_EBUS_H
-#define __SPARC64_EBUS_H
-
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-
-struct linux_ebus_child {
-       struct linux_ebus_child         *next;
-       struct linux_ebus_device        *parent;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-
-struct linux_ebus_device {
-       struct of_device                ofdev;
-       struct linux_ebus_device        *next;
-       struct linux_ebus_child         *children;
-       struct linux_ebus               *bus;
-       struct device_node              *prom_node;
-       struct resource                  resource[PROMREG_MAX];
-       int                              num_addrs;
-       unsigned int                     irqs[PROMINTR_MAX];
-       int                              num_irqs;
-};
-#define to_ebus_device(d) container_of(d, struct linux_ebus_device, ofdev.dev)
-
-struct linux_ebus {
-       struct of_device                ofdev;
-       struct linux_ebus               *next;
-       struct linux_ebus_device        *devices;
-       struct pci_dev                  *self;
-       int                              index;
-       int                              is_rio;
-       struct device_node              *prom_node;
-};
-#define to_ebus(d) container_of(d, struct linux_ebus, ofdev.dev)
-
-struct ebus_dma_info {
-       spinlock_t      lock;
-       void __iomem    *regs;
-
-       unsigned int    flags;
-#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER                0x00000001
-#define EBUS_DMA_FLAG_TCI_DISABLE              0x00000002
-
-       /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
-        * set.
-        */
-       void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
-       void *client_cookie;
-       unsigned int    irq;
-#define EBUS_DMA_EVENT_ERROR   1
-#define EBUS_DMA_EVENT_DMA     2
-#define EBUS_DMA_EVENT_DEVICE  4
-
-       unsigned char   name[64];
-};
-
-extern int ebus_dma_register(struct ebus_dma_info *p);
-extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
-extern void ebus_dma_unregister(struct ebus_dma_info *p);
-extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
-                           size_t len);
-extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
-extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
-extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
-extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
-
-extern struct linux_ebus               *ebus_chain;
-
-extern void ebus_init(void);
-
-#define for_each_ebus(bus)                                             \
-        for((bus) = ebus_chain; (bus); (bus) = (bus)->next)
-
-#define for_each_ebusdev(dev, bus)                                     \
-        for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
-
-#define for_each_edevchild(dev, child)                                 \
-        for((child) = (dev)->children; (child); (child) = (child)->next)
-
-#endif /* !(__SPARC64_EBUS_H) */
diff --git a/arch/sparc/include/asm/ebus_dma.h b/arch/sparc/include/asm/ebus_dma.h
new file mode 100644 (file)
index 0000000..f07a5b5
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef __ASM_SPARC_EBUS_DMA_H
+#define __ASM_SPARC_EBUS_DMA_H
+
+struct ebus_dma_info {
+       spinlock_t      lock;
+       void __iomem    *regs;
+
+       unsigned int    flags;
+#define EBUS_DMA_FLAG_USE_EBDMA_HANDLER                0x00000001
+#define EBUS_DMA_FLAG_TCI_DISABLE              0x00000002
+
+       /* These are only valid is EBUS_DMA_FLAG_USE_EBDMA_HANDLER is
+        * set.
+        */
+       void (*callback)(struct ebus_dma_info *p, int event, void *cookie);
+       void *client_cookie;
+       unsigned int    irq;
+#define EBUS_DMA_EVENT_ERROR   1
+#define EBUS_DMA_EVENT_DMA     2
+#define EBUS_DMA_EVENT_DEVICE  4
+
+       unsigned char   name[64];
+};
+
+extern int ebus_dma_register(struct ebus_dma_info *p);
+extern int ebus_dma_irq_enable(struct ebus_dma_info *p, int on);
+extern void ebus_dma_unregister(struct ebus_dma_info *p);
+extern int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr,
+                           size_t len);
+extern void ebus_dma_prepare(struct ebus_dma_info *p, int write);
+extern unsigned int ebus_dma_residue(struct ebus_dma_info *p);
+extern unsigned int ebus_dma_addr(struct ebus_dma_info *p);
+extern void ebus_dma_enable(struct ebus_dma_info *p, int on);
+
+#endif /* __ASM_SPARC_EBUS_DMA_H */
index d043f80bc2fd4b858a260c91d00e1592bc780caf..b7ab605478270779478103013c5fca34ea55f3f4 100644 (file)
@@ -105,11 +105,8 @@ typedef struct {
 #define ELF_DATA       ELFDATA2MSB
 
 #define USE_ELF_CORE_DUMP
-#ifndef CONFIG_SUN4
+
 #define ELF_EXEC_PAGESIZE      4096
-#else
-#define ELF_EXEC_PAGESIZE      8192
-#endif
 
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
@@ -126,7 +123,7 @@ typedef struct {
 /* Sun4c has none of the capabilities, most sun4m's have them all.
  * XXX This is gross, set some global variable at boot time. -DaveM
  */
-#define ELF_HWCAP      ((ARCH_SUN4C_SUN4) ? 0 : \
+#define ELF_HWCAP      ((ARCH_SUN4C) ? 0 : \
                         (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
                          HWCAP_SPARC_SWAP | \
                          ((srmmu_modtype != Cypress && \
index 788cbc46a1164a71d353d741cc854066d103769f..57f1b303ad54e94215c531452be0bab94043662d 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * fhc.h: Structures for central/fhc pseudo driver on Sunfire/Starfire/Wildfire.
+/* fhc.h: FHC and Clock board register definitions.
  *
  * Copyright (C) 1997, 1999 David S. Miller (davem@redhat.com)
  */
@@ -7,14 +6,6 @@
 #ifndef _SPARC64_FHC_H
 #define _SPARC64_FHC_H
 
-#include <linux/timer.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/upa.h>
-
-struct linux_fhc;
-
 /* Clock board register offsets. */
 #define CLOCK_CTRL     0x00UL  /* Main control */
 #define CLOCK_STAT1    0x10UL  /* Status one */
@@ -29,21 +20,7 @@ struct linux_fhc;
 #define CLOCK_CTRL_MLED                0x02    /* Mid LED, 1 == on */
 #define CLOCK_CTRL_RLED                0x01    /* RIght LED, 1 == on */
 
-struct linux_central {
-       struct linux_fhc                *child;
-       unsigned long                   cfreg;
-       unsigned long                   clkregs;
-       unsigned long                   clkver;
-       int                             slots;
-       struct device_node              *prom_node;
-
-       struct linux_prom_ranges        central_ranges[PROMREG_MAX];
-       int                             num_central_ranges;
-};
-
 /* Firehose controller register offsets */
-struct fhc_regs {
-       unsigned long                   pregs;  /* FHC internal regs */
 #define FHC_PREGS_ID   0x00UL  /* FHC ID */
 #define  FHC_ID_VERS           0xf0000000 /* Version of this FHC               */
 #define  FHC_ID_PARTID         0x0ffff000 /* Part ID code (0x0f9f == FHC)      */
@@ -90,32 +67,14 @@ struct fhc_regs {
 #define  FHC_JTAG_CTRL_MENAB   0x80000000 /* Indicates this is JTAG Master      */
 #define  FHC_JTAG_CTRL_MNONE   0x40000000 /* Indicates no JTAG Master present   */
 #define FHC_PREGS_JCMD 0x100UL /* FHC JTAG Command Register */
-       unsigned long                   ireg;   /* FHC IGN reg */
 #define FHC_IREG_IGN   0x00UL  /* This FHC's IGN */
-       unsigned long                   ffregs; /* FHC fanfail regs */
 #define FHC_FFREGS_IMAP        0x00UL  /* FHC Fanfail IMAP */
 #define FHC_FFREGS_ICLR        0x10UL  /* FHC Fanfail ICLR */
-       unsigned long                   sregs;  /* FHC system regs */
 #define FHC_SREGS_IMAP 0x00UL  /* FHC System IMAP */
 #define FHC_SREGS_ICLR 0x10UL  /* FHC System ICLR */
-       unsigned long                   uregs;  /* FHC uart regs */
 #define FHC_UREGS_IMAP 0x00UL  /* FHC Uart IMAP */
 #define FHC_UREGS_ICLR 0x10UL  /* FHC Uart ICLR */
-       unsigned long                   tregs;  /* FHC TOD regs */
 #define FHC_TREGS_IMAP 0x00UL  /* FHC TOD IMAP */
 #define FHC_TREGS_ICLR 0x10UL  /* FHC TOD ICLR */
-};
-
-struct linux_fhc {
-       struct linux_fhc                *next;
-       struct linux_central            *parent;        /* NULL if not central FHC */
-       struct fhc_regs                 fhc_regs;
-       int                             board;
-       int                             jtag_master;
-       struct device_node              *prom_node;
-
-       struct linux_prom_ranges        fhc_ranges[PROMREG_MAX];
-       int                             num_fhc_ranges;
-};
 
 #endif /* !(_SPARC64_FHC_H) */
index ae3f00bf22ff91d990ab4c47aaa200729c570181..c792830636decfa4c3652d25d9947837bdf362f2 100644 (file)
@@ -6,6 +6,9 @@
 #ifndef __ASM_SPARC_FLOPPY_H
 #define __ASM_SPARC_FLOPPY_H
 
+#include <linux/of.h>
+#include <linux/of_device.h>
+
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -343,7 +346,7 @@ static int sun_floppy_init(void)
        r.flags = fd_regs[0].which_io;
        r.start = fd_regs[0].phys_addr;
        sun_fdc = (struct sun_flpy_controller *)
-           sbus_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+           of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
 
        /* Last minute sanity check... */
        if(sun_fdc->status_82072 == 0xff) {
@@ -385,4 +388,15 @@ static int sparc_eject(void)
 
 #define EXTRA_FLOPPY_PARAMS
 
+static DEFINE_SPINLOCK(dma_spin_lock);
+
+#define claim_dma_lock() \
+({     unsigned long flags; \
+       spin_lock_irqsave(&dma_spin_lock, flags); \
+       flags; \
+})
+
+#define release_dma_lock(__flags) \
+       spin_unlock_irqrestore(&dma_spin_lock, __flags);
+
 #endif /* !(__ASM_SPARC_FLOPPY_H) */
index c39db1060bc7adc13b0a05652a079a8ab5010a0c..36439d67ad7111cadbc4cc3810e9577932211094 100644 (file)
@@ -1,6 +1,6 @@
 /* floppy.h: Sparc specific parts of the Floppy driver.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  *
  * Ultra/PCI support added: Sep 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -9,18 +9,11 @@
 #ifndef __ASM_SPARC64_FLOPPY_H
 #define __ASM_SPARC64_FLOPPY_H
 
-#include <linux/init.h>
-#include <linux/pci.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
 
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/idprom.h>
-#include <asm/oplib.h>
 #include <asm/auxio.h>
-#include <asm/sbus.h>
-#include <asm/irq.h>
-
 
 /*
  * Define this to enable exchanging drive 0 and 1 if only drive 1 is
@@ -50,7 +43,7 @@ struct sun_flpy_controller {
 /* You'll only ever find one controller on an Ultra anyways. */
 static struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
 unsigned long fdc_status;
-static struct sbus_dev *floppy_sdev = NULL;
+static struct of_device *floppy_op = NULL;
 
 struct sun_floppy_ops {
        unsigned char   (*fd_inb) (unsigned long port);
@@ -291,12 +284,11 @@ static int sun_fd_eject(int drive)
        return 0;
 }
 
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 
 static struct ebus_dma_info sun_pci_fd_ebus_dma;
-static struct pci_dev *sun_pci_ebus_dev;
+static struct device *sun_floppy_dev;
 static int sun_pci_broken_drive = -1;
 
 struct sun_pci_dma_op {
@@ -377,7 +369,7 @@ static void sun_pci_fd_enable_dma(void)
        sun_pci_dma_pending.addr = -1U;
 
        sun_pci_dma_current.addr =
-               pci_map_single(sun_pci_ebus_dev,
+               dma_map_single(sun_floppy_dev,
                               sun_pci_dma_current.buf,
                               sun_pci_dma_current.len,
                               sun_pci_dma_current.direction);
@@ -394,7 +386,7 @@ static void sun_pci_fd_disable_dma(void)
 {
        ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
        if (sun_pci_dma_current.addr != -1U)
-               pci_unmap_single(sun_pci_ebus_dev,
+               dma_unmap_single(sun_floppy_dev,
                                 sun_pci_dma_current.addr,
                                 sun_pci_dma_current.len,
                                 sun_pci_dma_current.direction);
@@ -404,9 +396,9 @@ static void sun_pci_fd_disable_dma(void)
 static void sun_pci_fd_set_dma_mode(int mode)
 {
        if (mode == DMA_MODE_WRITE)
-               sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
+               sun_pci_dma_pending.direction = DMA_TO_DEVICE;
        else
-               sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
+               sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
 
        ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
 }
@@ -538,80 +530,84 @@ static int sun_pci_fd_test_drive(unsigned long port, int drive)
 #undef MSR
 #undef DOR
 
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_PCI
-static int __init ebus_fdthree_p(struct linux_ebus_device *edev)
+static int __init ebus_fdthree_p(struct device_node *dp)
 {
-       if (!strcmp(edev->prom_node->name, "fdthree"))
+       if (!strcmp(dp->name, "fdthree"))
                return 1;
-       if (!strcmp(edev->prom_node->name, "floppy")) {
+       if (!strcmp(dp->name, "floppy")) {
                const char *compat;
 
-               compat = of_get_property(edev->prom_node,
-                                        "compatible", NULL);
+               compat = of_get_property(dp, "compatible", NULL);
                if (compat && !strcmp(compat, "fdthree"))
                        return 1;
        }
        return 0;
 }
-#endif
 
 static unsigned long __init sun_floppy_init(void)
 {
-       char state[128];
-       struct sbus_bus *bus;
-       struct sbus_dev *sdev = NULL;
        static int initialized = 0;
+       struct device_node *dp;
+       struct of_device *op;
+       const char *prop;
+       char state[128];
 
        if (initialized)
                return sun_floppy_types[0];
        initialized = 1;
 
-       for_all_sbusdev (sdev, bus) {
-               if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
+       op = NULL;
+
+       for_each_node_by_name(dp, "SUNW,fdtwo") {
+               if (strcmp(dp->parent->name, "sbus"))
+                       continue;
+               op = of_find_device_by_node(dp);
+               if (op)
                        break;
        }
-       if(sdev) {
-               floppy_sdev = sdev;
-               FLOPPY_IRQ = sdev->irqs[0];
+       if (op) {
+               floppy_op = op;
+               FLOPPY_IRQ = op->irqs[0];
        } else {
-#ifdef CONFIG_PCI
-               struct linux_ebus *ebus;
-               struct linux_ebus_device *edev = NULL;
-               unsigned long config = 0;
+               struct device_node *ebus_dp;
                void __iomem *auxio_reg;
                const char *state_prop;
+               unsigned long config;
 
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (ebus_fdthree_p(edev))
-                                       goto ebus_done;
+               dp = NULL;
+               for_each_node_by_name(ebus_dp, "ebus") {
+                       for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+                               if (ebus_fdthree_p(dp))
+                                       goto found_fdthree;
                        }
                }
-       ebus_done:
-               if (!edev)
+       found_fdthree:
+               if (!dp)
+                       return 0;
+
+               op = of_find_device_by_node(dp);
+               if (!op)
                        return 0;
 
-               state_prop = of_get_property(edev->prom_node, "status", NULL);
+               state_prop = of_get_property(op->node, "status", NULL);
                if (state_prop && !strncmp(state_prop, "disabled", 8))
                        return 0;
 
-               FLOPPY_IRQ = edev->irqs[0];
+               FLOPPY_IRQ = op->irqs[0];
 
                /* Make sure the high density bit is set, some systems
                 * (most notably Ultra5/Ultra10) come up with it clear.
                 */
-               auxio_reg = (void __iomem *) edev->resource[2].start;
+               auxio_reg = (void __iomem *) op->resource[2].start;
                writel(readl(auxio_reg)|0x2, auxio_reg);
 
-               sun_pci_ebus_dev = ebus->self;
+               sun_floppy_dev = &op->dev;
 
                spin_lock_init(&sun_pci_fd_ebus_dma.lock);
 
                /* XXX ioremap */
                sun_pci_fd_ebus_dma.regs = (void __iomem *)
-                       edev->resource[1].start;
+                       op->resource[1].start;
                if (!sun_pci_fd_ebus_dma.regs)
                        return 0;
 
@@ -625,7 +621,7 @@ static unsigned long __init sun_floppy_init(void)
                        return 0;
 
                /* XXX ioremap */
-               sun_fdc = (struct sun_flpy_controller *)edev->resource[0].start;
+               sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
 
                sun_fdops.fd_inb = sun_pci_fd_inb;
                sun_fdops.fd_outb = sun_pci_fd_outb;
@@ -662,12 +658,15 @@ static unsigned long __init sun_floppy_init(void)
                /*
                 * Find NS87303 SuperIO config registers (through ecpp).
                 */
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (!strcmp(edev->prom_node->name, "ecpp")) {
-                                       config = edev->resource[1].start;
-                                       goto config_done;
-                               }
+               config = 0;
+               for (dp = ebus_dp->child; dp; dp = dp->sibling) {
+                       if (!strcmp(dp->name, "ecpp")) {
+                               struct of_device *ecpp_op;
+
+                               ecpp_op = of_find_device_by_node(dp);
+                               if (ecpp_op)
+                                       config = ecpp_op->resource[1].start;
+                               goto config_done;
                        }
                }
        config_done:
@@ -716,26 +715,23 @@ static unsigned long __init sun_floppy_init(void)
 #endif /* PCI_FDC_SWAP_DRIVES */
 
                return sun_floppy_types[0];
-#else
-               return 0;
-#endif
        }
-       prom_getproperty(sdev->prom_node, "status", state, sizeof(state));
-       if(!strncmp(state, "disabled", 8))
+       prop = of_get_property(op->node, "status", NULL);
+       if (prop && !strncmp(state, "disabled", 8))
                return 0;
 
        /*
-        * We cannot do sbus_ioremap here: it does request_region,
+        * We cannot do of_ioremap here: it does request_region,
         * which the generic floppy driver tries to do once again.
         * But we must use the sdev resource values as they have
         * had parent ranges applied.
         */
        sun_fdc = (struct sun_flpy_controller *)
-               (sdev->resource[0].start +
-                ((sdev->resource[0].flags & 0x1ffUL) << 32UL));
+               (op->resource[0].start +
+                ((op->resource[0].flags & 0x1ffUL) << 32UL));
 
        /* Last minute sanity check... */
-       if(sbus_readb(&sun_fdc->status1_82077) == 0xff) {
+       if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
                sun_fdc = (struct sun_flpy_controller *)-1;
                return 0;
        }
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
new file mode 100644 (file)
index 0000000..a0e3ac0
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __ASM_SPARC_GPIO_H
+#define __ASM_SPARC_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+       return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+       __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+       return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+       return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* __ASM_SPARC_GPIO_H */
index 96823b47fd453e4108b25039523c8b97309c1208..01ab2f613e91e44e8d74f1b1c371c3c83304335b 100644 (file)
@@ -55,8 +55,4 @@ struct iounit_struct {
 #define IOUNIT_BMAPM_START     IOUNIT_BMAP2_END
 #define IOUNIT_BMAPM_END       ((IOUNIT_DMA_SIZE - IOUNIT_DVMA_SIZE) >> PAGE_SHIFT)
 
-extern __u32 iounit_map_dma_init(struct sbus_bus *, int);
-#define iounit_map_dma_finish(sbus, addr, len) mmu_release_scsi_one(addr, len, sbus)
-extern __u32 iounit_map_dma_page(__u32, void *, struct sbus_bus *);
-
 #endif /* !(_SPARC_IO_UNIT_H) */
index 10d7da450070c952a8e2094375676067b50752de..93fe21e02c86b0c7607f06c813532223220a68cf 100644 (file)
@@ -292,14 +292,6 @@ struct pci_dev;
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
-/*
- * Bus number may be in res->flags... somewhere.
- */
-extern void __iomem *sbus_ioremap(struct resource *res, unsigned long offset,
-    unsigned long size, char *name);
-extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
-
-
 /*
  * At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
  * so rtc_port is static in it. This should not change unless a new
@@ -308,6 +300,17 @@ extern void sbus_iounmap(volatile void __iomem *vaddr, unsigned long size);
 #define RTC_PORT(x)   (rtc_port + (x))
 #define RTC_ALWAYS_BCD  0
 
+static inline int sbus_can_dma_64bit(void)
+{
+       return 0; /* actually, sparc_cpu_model==sun4d */
+}
+static inline int sbus_can_burst64(void)
+{
+       return 0; /* actually, sparc_cpu_model==sun4d */
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
+
 #endif
 
 #define __ARCH_HAS_NO_PAGE_ZERO_MAPPED         1
index 0bff078ffdd05a223060c5a06f9428108949baa5..4aee21dc9c6f10d8f6d0f908177f7c56f5095c72 100644 (file)
@@ -482,18 +482,16 @@ struct pci_dev;
 extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
 extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
 
-/* Similarly for SBUS. */
-#define sbus_ioremap(__res, __offset, __size, __name) \
-({     unsigned long __ret; \
-       __ret  = (__res)->start + (((__res)->flags & 0x1ffUL) << 32UL); \
-       __ret += (unsigned long) (__offset); \
-       if (! request_region((__ret), (__size), (__name))) \
-               __ret = 0UL; \
-       (void __iomem *) __ret; \
-})
-
-#define sbus_iounmap(__addr, __size)   \
-       release_region((unsigned long)(__addr), (__size))
+static inline int sbus_can_dma_64bit(void)
+{
+       return 1;
+}
+static inline int sbus_can_burst64(void)
+{
+       return 1;
+}
+struct device;
+extern void sbus_set_sbus64(struct device *, int);
 
 /*
  * Convert a physical pointer to a virtual kernel pointer for /dev/mem
index d7b9afcba08bf433c87d8569f0169d1eaec68343..caf798b5619174d3b07bb39ea17f342f16548aaf 100644 (file)
@@ -48,6 +48,9 @@ struct strbuf {
        unsigned long           strbuf_control;
        unsigned long           strbuf_pflush;
        unsigned long           strbuf_fsync;
+       unsigned long           strbuf_err_stat;
+       unsigned long           strbuf_tag_diag;
+       unsigned long           strbuf_line_diag;
        unsigned long           strbuf_ctxflush;
        unsigned long           strbuf_ctxmatch_base;
        unsigned long           strbuf_flushflag_pa;
index e3dd9303643dd8f161fd5fd5234abac5a5b77a31..71673eca3660be0dcce7359c88aa9edcae0e7ee1 100644 (file)
@@ -56,7 +56,6 @@ extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
                                    unsigned long imap_base,
                                    unsigned long iclr_base);
 extern void sun4u_destroy_msi(unsigned int virt_irq);
-extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
 
 extern unsigned char virt_irq_alloc(unsigned int dev_handle,
                                    unsigned int dev_ino);
index e9c0fcc25c6f44e2c729cda84994949b32606bb0..7238d174e0e30509eb0b6ee235b125ad393096ab 100644 (file)
@@ -7,12 +7,8 @@
 #include <asm/io.h>
 
 #ifndef RTC_PORT
-#ifdef CONFIG_PCI
-extern unsigned long ds1287_regs;
-#else
-#define ds1287_regs (0UL)
-#endif
-#define RTC_PORT(x)    (ds1287_regs + (x))
+extern unsigned long cmos_regs;
+#define RTC_PORT(x)    (cmos_regs + (x))
 #define RTC_ALWAYS_BCD 0
 #endif
 
@@ -29,6 +25,4 @@ outb_p((addr),RTC_PORT(0)); \
 outb_p((val),RTC_PORT(1)); \
 })
 
-#define RTC_IRQ 8
-
 #endif /* __ASM_SPARC64_MC146818RTC_H */
diff --git a/arch/sparc/include/asm/memctrl.h b/arch/sparc/include/asm/memctrl.h
new file mode 100644 (file)
index 0000000..4065c56
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _SPARC_MEMCTRL_H
+#define _SPARC_MEMCTRL_H
+
+typedef int (*dimm_printer_t)(int synd_code, unsigned long paddr, char *buf, int buflen);
+
+int register_dimm_printer(dimm_printer_t func);
+void unregister_dimm_printer(dimm_printer_t func);
+
+#endif /* _SPARC_MEMCTRL_H */
diff --git a/arch/sparc/include/asm/mostek.h b/arch/sparc/include/asm/mostek.h
deleted file mode 100644 (file)
index 433be3e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_MOSTEK_H
-#define ___ASM_SPARC_MOSTEK_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/mostek_64.h>
-#else
-#include <asm/mostek_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/mostek_32.h b/arch/sparc/include/asm/mostek_32.h
deleted file mode 100644 (file)
index a99590c..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- * Added intersil code 05/25/98 Chris Davis (cdavis@cois.on.ca)
- */
-
-#ifndef _SPARC_MOSTEK_H
-#define _SPARC_MOSTEK_H
-
-#include <asm/idprom.h>
-#include <asm/io.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- */
-#define mostek_read(_addr)             readb(_addr)
-#define mostek_write(_addr,_val)       writeb(_val, _addr)
-#define MOSTEK_EEPROM          0x0000UL
-#define MOSTEK_IDPROM          0x07d8UL
-#define MOSTEK_CREG            0x07f8UL
-#define MOSTEK_SEC             0x07f9UL
-#define MOSTEK_MIN             0x07faUL
-#define MOSTEK_HOUR            0x07fbUL
-#define MOSTEK_DOW             0x07fcUL
-#define MOSTEK_DOM             0x07fdUL
-#define MOSTEK_MONTH           0x07feUL
-#define MOSTEK_YEAR            0x07ffUL
-
-struct mostek48t02 {
-       volatile char eeprom[2008];     /* This is the eeprom, don't touch! */
-       struct idprom idprom;           /* The idprom lives here. */
-       volatile unsigned char creg;    /* Control register */
-       volatile unsigned char sec;     /* Seconds (0-59) */
-       volatile unsigned char min;     /* Minutes (0-59) */
-       volatile unsigned char hour;    /* Hour (0-23) */
-       volatile unsigned char dow;     /* Day of the week (1-7) */
-       volatile unsigned char dom;     /* Day of the month (1-31) */
-       volatile unsigned char month;   /* Month of year (1-12) */
-       volatile unsigned char year;    /* Year (0-99) */
-};
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define        MSTK_CREG_WRITE 0x80    /* Must set this before placing values. */
-#define        MSTK_CREG_READ  0x40    /* Stop updates to allow a clean read. */
-#define        MSTK_CREG_SIGN  0x20    /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define        MSTK_STOP       0x80    /* Stop the clock oscillator. (sec) */
-#define        MSTK_KICK_START 0x80    /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40    /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define        MSTK_SEC_MASK   0x7f
-#define        MSTK_MIN_MASK   0x7f
-#define        MSTK_HOUR_MASK  0x3f
-#define        MSTK_DOW_MASK   0x07
-#define        MSTK_DOM_MASK   0x3f
-#define        MSTK_MONTH_MASK 0x1f
-#define        MSTK_YEAR_MASK  0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,var,mask) (MSTK_REGVAL_TO_DECIMAL(((struct mostek48t02 *)regs)->var & MSTK_ ## mask ## _MASK))
-#define MSTK_SET(regs,var,value,mask) do { ((struct mostek48t02 *)regs)->var &= ~(MSTK_ ## mask ## _MASK); ((struct mostek48t02 *)regs)->var |= MSTK_DECIMAL_TO_REGVAL(value) & (MSTK_ ## mask ## _MASK); } while (0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define        MSTK_REG_CREG(regs)     (((struct mostek48t02 *)regs)->creg)
-#define        MSTK_REG_SEC(regs)      MSTK_GET(regs,sec,SEC)
-#define        MSTK_REG_MIN(regs)      MSTK_GET(regs,min,MIN)
-#define        MSTK_REG_HOUR(regs)     MSTK_GET(regs,hour,HOUR)
-#define        MSTK_REG_DOW(regs)      MSTK_GET(regs,dow,DOW)
-#define        MSTK_REG_DOM(regs)      MSTK_GET(regs,dom,DOM)
-#define        MSTK_REG_MONTH(regs)    MSTK_GET(regs,month,MONTH)
-#define        MSTK_REG_YEAR(regs)     MSTK_GET(regs,year,YEAR)
-
-#define        MSTK_SET_REG_SEC(regs,value)    MSTK_SET(regs,sec,value,SEC)
-#define        MSTK_SET_REG_MIN(regs,value)    MSTK_SET(regs,min,value,MIN)
-#define        MSTK_SET_REG_HOUR(regs,value)   MSTK_SET(regs,hour,value,HOUR)
-#define        MSTK_SET_REG_DOW(regs,value)    MSTK_SET(regs,dow,value,DOW)
-#define        MSTK_SET_REG_DOM(regs,value)    MSTK_SET(regs,dom,value,DOM)
-#define        MSTK_SET_REG_MONTH(regs,value)  MSTK_SET(regs,month,value,MONTH)
-#define        MSTK_SET_REG_YEAR(regs,value)   MSTK_SET(regs,year,value,YEAR)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-struct mostek48t08 {
-       char offset[6*1024];         /* Magic things may be here, who knows? */
-       struct mostek48t02 regs;     /* Here is what we are interested in.   */
-};
-
-#ifdef CONFIG_SUN4
-enum sparc_clock_type {        MSTK48T02, MSTK48T08, \
-INTERSIL, MSTK_INVALID };
-#else
-enum sparc_clock_type {        MSTK48T02, MSTK48T08, \
-MSTK_INVALID };
-#endif
-
-#ifdef CONFIG_SUN4
-/* intersil on a sun 4/260 code  data from harris doc */
-struct intersil_dt {
-        volatile unsigned char int_csec;
-        volatile unsigned char int_hour;
-        volatile unsigned char int_min;
-        volatile unsigned char int_sec;
-        volatile unsigned char int_month;
-        volatile unsigned char int_day;
-        volatile unsigned char int_year;
-        volatile unsigned char int_dow;
-};
-
-struct intersil {
-       struct intersil_dt clk;
-       struct intersil_dt cmp;
-       volatile unsigned char int_intr_reg;
-       volatile unsigned char int_cmd_reg;
-};
-
-#define INTERSIL_STOP        0x0
-#define INTERSIL_START       0x8
-#define INTERSIL_INTR_DISABLE   0x0
-#define INTERSIL_INTR_ENABLE   0x10
-#define INTERSIL_32K           0x0
-#define INTERSIL_NORMAL                0x0
-#define INTERSIL_24H           0x4
-#define INTERSIL_INT_100HZ     0x2
-
-/* end of intersil info */
-#endif
-
-#endif /* !(_SPARC_MOSTEK_H) */
diff --git a/arch/sparc/include/asm/mostek_64.h b/arch/sparc/include/asm/mostek_64.h
deleted file mode 100644 (file)
index c5652de..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/* mostek.h:  Describes the various Mostek time of day clock registers.
- *
- * Copyright (C) 1995 David S. Miller (davem@davemloft.net)
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _SPARC64_MOSTEK_H
-#define _SPARC64_MOSTEK_H
-
-#include <asm/idprom.h>
-
-/*       M48T02 Register Map (adapted from Sun NVRAM/Hostid FAQ)
- *
- *                             Data
- * Address                                                 Function
- *        Bit 7 Bit 6 Bit 5 Bit 4Bit 3 Bit 2 Bit 1 Bit 0
- *   7ff  -     -     -     -    -     -     -     -       Year 00-99
- *   7fe  0     0     0     -    -     -     -     -      Month 01-12
- *   7fd  0     0     -     -    -     -     -     -       Date 01-31
- *   7fc  0     FT    0     0    0     -     -     -        Day 01-07
- *   7fb  KS    0     -     -    -     -     -     -      Hours 00-23
- *   7fa  0     -     -     -    -     -     -     -    Minutes 00-59
- *   7f9  ST    -     -     -    -     -     -     -    Seconds 00-59
- *   7f8  W     R     S     -    -     -     -     -    Control
- *
- *   * ST is STOP BIT
- *   * W is WRITE BIT
- *   * R is READ BIT
- *   * S is SIGN BIT
- *   * FT is FREQ TEST BIT
- *   * KS is KICK START BIT
- */
-
-/* The Mostek 48t02 real time clock and NVRAM chip. The registers
- * other than the control register are in binary coded decimal. Some
- * control bits also live outside the control register.
- *
- * We now deal with physical addresses for I/O to the chip. -DaveM
- */
-static inline u8 mostek_read(void __iomem *addr)
-{
-       u8 ret;
-
-       __asm__ __volatile__("lduba     [%1] %2, %0"
-                            : "=r" (ret)
-                            : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-       return ret;
-}
-
-static inline void mostek_write(void __iomem *addr, u8 val)
-{
-       __asm__ __volatile__("stba      %0, [%1] %2"
-                            : /* no outputs */
-                            : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E));
-}
-
-#define MOSTEK_EEPROM          0x0000UL
-#define MOSTEK_IDPROM          0x07d8UL
-#define MOSTEK_CREG            0x07f8UL
-#define MOSTEK_SEC             0x07f9UL
-#define MOSTEK_MIN             0x07faUL
-#define MOSTEK_HOUR            0x07fbUL
-#define MOSTEK_DOW             0x07fcUL
-#define MOSTEK_DOM             0x07fdUL
-#define MOSTEK_MONTH           0x07feUL
-#define MOSTEK_YEAR            0x07ffUL
-
-extern spinlock_t mostek_lock;
-extern void __iomem *mstk48t02_regs;
-
-/* Control register values. */
-#define        MSTK_CREG_WRITE 0x80    /* Must set this before placing values. */
-#define        MSTK_CREG_READ  0x40    /* Stop updates to allow a clean read. */
-#define        MSTK_CREG_SIGN  0x20    /* Slow/speed clock in calibration mode. */
-
-/* Control bits that live in the other registers. */
-#define        MSTK_STOP       0x80    /* Stop the clock oscillator. (sec) */
-#define        MSTK_KICK_START 0x80    /* Kick start the clock chip. (hour) */
-#define MSTK_FREQ_TEST 0x40    /* Frequency test mode. (day) */
-
-#define MSTK_YEAR_ZERO       1968   /* If year reg has zero, it is 1968. */
-#define MSTK_CVT_YEAR(yr)  ((yr) + MSTK_YEAR_ZERO)
-
-/* Masks that define how much space each value takes up. */
-#define        MSTK_SEC_MASK   0x7f
-#define        MSTK_MIN_MASK   0x7f
-#define        MSTK_HOUR_MASK  0x3f
-#define        MSTK_DOW_MASK   0x07
-#define        MSTK_DOM_MASK   0x3f
-#define        MSTK_MONTH_MASK 0x1f
-#define        MSTK_YEAR_MASK  0xffU
-
-/* Binary coded decimal conversion macros. */
-#define MSTK_REGVAL_TO_DECIMAL(x)  (((x) & 0x0F) + 0x0A * ((x) >> 0x04))
-#define MSTK_DECIMAL_TO_REGVAL(x)  ((((x) / 0x0A) << 0x04) + ((x) % 0x0A))
-
-/* Generic register set and get macros for internal use. */
-#define MSTK_GET(regs,name)    \
-       (MSTK_REGVAL_TO_DECIMAL(mostek_read(regs + MOSTEK_ ## name) & MSTK_ ## name ## _MASK))
-#define MSTK_SET(regs,name,value) \
-do {   u8 __val = mostek_read(regs + MOSTEK_ ## name); \
-       __val &= ~(MSTK_ ## name ## _MASK); \
-       __val |= (MSTK_DECIMAL_TO_REGVAL(value) & \
-                 (MSTK_ ## name ## _MASK)); \
-       mostek_write(regs + MOSTEK_ ## name, __val); \
-} while(0)
-
-/* Macros to make register access easier on our fingers. These give you
- * the decimal value of the register requested if applicable. You pass
- * the a pointer to a 'struct mostek48t02'.
- */
-#define        MSTK_REG_CREG(regs)     (mostek_read((regs) + MOSTEK_CREG))
-#define        MSTK_REG_SEC(regs)      MSTK_GET(regs,SEC)
-#define        MSTK_REG_MIN(regs)      MSTK_GET(regs,MIN)
-#define        MSTK_REG_HOUR(regs)     MSTK_GET(regs,HOUR)
-#define        MSTK_REG_DOW(regs)      MSTK_GET(regs,DOW)
-#define        MSTK_REG_DOM(regs)      MSTK_GET(regs,DOM)
-#define        MSTK_REG_MONTH(regs)    MSTK_GET(regs,MONTH)
-#define        MSTK_REG_YEAR(regs)     MSTK_GET(regs,YEAR)
-
-#define        MSTK_SET_REG_SEC(regs,value)    MSTK_SET(regs,SEC,value)
-#define        MSTK_SET_REG_MIN(regs,value)    MSTK_SET(regs,MIN,value)
-#define        MSTK_SET_REG_HOUR(regs,value)   MSTK_SET(regs,HOUR,value)
-#define        MSTK_SET_REG_DOW(regs,value)    MSTK_SET(regs,DOW,value)
-#define        MSTK_SET_REG_DOM(regs,value)    MSTK_SET(regs,DOM,value)
-#define        MSTK_SET_REG_MONTH(regs,value)  MSTK_SET(regs,MONTH,value)
-#define        MSTK_SET_REG_YEAR(regs,value)   MSTK_SET(regs,YEAR,value)
-
-
-/* The Mostek 48t08 clock chip. Found on Sun4m's I think. It has the
- * same (basically) layout of the 48t02 chip except for the extra
- * NVRAM on board (8 KB against the 48t02's 2 KB).
- */
-#define MOSTEK_48T08_OFFSET    0x0000UL        /* Lower NVRAM portions */
-#define MOSTEK_48T08_48T02     0x1800UL        /* Offset to 48T02 chip */
-
-/* SUN5 systems usually have 48t59 model clock chipsets.  But we keep the older
- * clock chip definitions around just in case.
- */
-#define MOSTEK_48T59_OFFSET    0x0000UL        /* Lower NVRAM portions */
-#define MOSTEK_48T59_48T02     0x1800UL        /* Offset to 48T02 chip */
-
-#endif /* !(_SPARC64_MOSTEK_H) */
index 1a7544ceb57416c71f5de6e705f368ce8f79dab5..4ade0c8a2c79489b1c3d2e4a0b8195b739c52035 100644 (file)
@@ -155,17 +155,6 @@ static inline void bw_set_ctrl(int cpu, unsigned ctrl)
                              "i" (ASI_M_CTL));
 }
 
-extern unsigned char cpu_leds[32];
-
-static inline void show_leds(int cpuid)
-{
-       cpuid &= 0x1e;
-       __asm__ __volatile__ ("stba %0, [%1] %2" : :
-                             "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
-                             "r" (ECSR_BASE(cpuid) | BB_LEDS),
-                             "i" (ASI_M_CTL));
-}
-
 static inline unsigned cc_get_ipen(void)
 {
        unsigned pending;
index bba777a416d3bf31b7ab4b5bb5a393ea7cc2c9f7..a5d9811f9697734863510a8b1c7336d228ac45ab 100644 (file)
@@ -30,6 +30,8 @@ struct of_device
 extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
 extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
 
+extern void of_propagate_archdata(struct of_device *bus);
+
 /* This is just here during the transition */
 #include <linux/of_platform.h>
 
index 2348ab90a57cfb769e6484e6463c90bc345821d4..90da99059f832b733f15d23612775502c34e4c66 100644 (file)
@@ -13,9 +13,6 @@
  *
  */
 
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-
 #define of_bus_type    of_platform_bus_type    /* for compatibility */
 
 #endif
index b2631da259e01ee61fc444003aaf4ba6f5d68697..699da05235c83f5f8c6afa4415775f17df7340e0 100644 (file)
@@ -21,7 +21,6 @@ enum prom_major_version {
        PROM_V2,      /* sun4c and early sun4m V2 prom */
        PROM_V3,      /* sun4m and later, up to sun4d/sun4e machines V3 */
        PROM_P1275,   /* IEEE compliant ISA based Sun PROM, only sun4u */
-       PROM_SUN4,    /* Old sun4 proms are totally different, but we'll shoehorn it to make it fit */
 };
 
 extern enum prom_major_version prom_vers;
index cf5fb70ca1c1c3f562bdeae825db12fda8f90963..d1806edc0958b7f81c2b9d38d06a2b9ab71b2c3a 100644 (file)
@@ -8,11 +8,8 @@
 #ifndef _SPARC_PAGE_H
 #define _SPARC_PAGE_H
 
-#ifdef CONFIG_SUN4
-#define PAGE_SHIFT   13
-#else
 #define PAGE_SHIFT   12
-#endif
+
 #ifndef __ASSEMBLY__
 /* I have my suspicions... -DaveM */
 #define PAGE_SIZE    (1UL << PAGE_SHIFT)
index b579b910ef5123b24c1fc02fc92c1d4520e6ea9e..4274ed13ddb2d6209fdc914db7d51f939ad4b06c 100644 (file)
@@ -38,6 +38,8 @@
 
 #ifndef __ASSEMBLY__
 
+#define WANT_PAGE_VIRTUAL
+
 extern void _clear_page(void *page);
 #define clear_page(X)  _clear_page((void *)(X))
 struct page;
index d9830621c906bb67dae70ebc65eed5addd0f4bff..dff3f0253aa891c90172b7baef03e767a5c9f90a 100644 (file)
@@ -8,7 +8,7 @@
 
 #include <linux/of_device.h>
 
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #include <asm/ns87303.h>
 #include <asm/prom.h>
 
@@ -215,7 +215,7 @@ static int __devexit ecpp_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id ecpp_match[] = {
+static const struct of_device_id ecpp_match[] = {
        {
                .name = "ecpp",
        },
index 0ee949d220c06d3c3a7beec15b19ca3abf33e367..b41c4c1981591b66df0a41b1c3d1e81b7099d400 100644 (file)
@@ -3,6 +3,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/dma-mapping.h>
+
 /* Can be used to override the logic in pci_scan_bus for skipping
  * already-configured bus numbers - to be used for buggy BIOSes
  * or architectures with incomplete PCI setup by the loader.
index 08237fda8874390b267a2036564f364e79eaf1a6..e0cabe790ec134e762e27b410012d90389a95825 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/swap.h>
 #include <asm/types.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/pgtsrmmu.h>
 #include <asm/vac-ops.h>
 #include <asm/oplib.h>
index bb9ec2cce355a56ed6822fda43fb8c9634d87c04..b049abf9902fdb42d4efe145d88a731dd4b6734b 100644 (file)
@@ -770,6 +770,8 @@ extern void sun4v_patch_tlb_handlers(void);
 
 extern unsigned long cmdline_memory_size;
 
+extern asmlinkage void do_sparc64_fault(struct pt_regs *regs);
+
 #endif /* !(__ASSEMBLY__) */
 
 #endif /* !(_SPARC64_PGTABLE_H) */
index fd55522481cd9dc0d14a14302446dff9d13017ee..900d44714f8dd8525776a17cdd4e40e2d2bf7a3e 100644 (file)
@@ -18,6 +18,7 @@
  */
 #include <linux/types.h>
 #include <linux/proc_fs.h>
+#include <linux/mutex.h>
 #include <asm/atomic.h>
 
 #define OF_ROOT_NODE_ADDR_CELLS_DEFAULT        2
@@ -73,6 +74,7 @@ struct of_irq_controller {
 
 extern struct device_node *of_find_node_by_cpuid(int cpuid);
 extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
+extern struct mutex of_set_property_mutex;
 extern int of_getintprop_default(struct device_node *np,
                                 const char *name,
                                 int def);
@@ -94,6 +96,16 @@ static inline void of_node_put(struct device_node *node)
 {
 }
 
+/* These routines are here to provide compatibility with how powerpc
+ * handles IRQ mapping for OF device nodes.  We precompute and permanently
+ * register them in the of_device objects, whereas powerpc computes them
+ * on request.
+ */
+extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
+static inline void irq_dispose_mapping(unsigned int virq)
+{
+}
+
 /*
  * NB:  This is here while we transition from using asm/prom.h
  * to linux/of.h
index 06e4914c13f4100182ccd5aa5720d3247e4469fa..3d3e9c161d8bdb41623a82aa97929fbd0be3b856 100644 (file)
@@ -113,6 +113,8 @@ struct sparc_trapf {
 
 #ifdef __KERNEL__
 
+#include <linux/threads.h>
+
 static inline int pt_regs_trap_type(struct pt_regs *regs)
 {
        return regs->magic & 0x1ff;
@@ -138,6 +140,7 @@ struct global_reg_snapshot {
        struct thread_info      *thread;
        unsigned long           pad1;
 };
+extern struct global_reg_snapshot global_reg_snapshot[NR_CPUS];
 
 #define __ARCH_WANT_COMPAT_SYS_PTRACE
 
diff --git a/arch/sparc/include/asm/reboot.h b/arch/sparc/include/asm/reboot.h
deleted file mode 100644 (file)
index 3f3f43f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC64_REBOOT_H
-#define _SPARC64_REBOOT_H
-
-extern void machine_alt_power_off(void);
-
-#endif /* _SPARC64_REBOOT_H */
diff --git a/arch/sparc/include/asm/rtc.h b/arch/sparc/include/asm/rtc.h
deleted file mode 100644 (file)
index f9ecb1f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * rtc.h: Definitions for access to the Mostek real time clock
- *
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- */
-
-#ifndef _RTC_H
-#define _RTC_H
-
-#include <linux/ioctl.h>
-
-struct rtc_time
-{
-       int     sec;    /* Seconds (0-59) */
-       int     min;    /* Minutes (0-59) */
-       int     hour;   /* Hour (0-23) */
-       int     dow;    /* Day of the week (1-7) */
-       int     dom;    /* Day of the month (1-31) */
-       int     month;  /* Month of year (1-12) */
-       int     year;   /* Year (0-99) */
-};
-
-#define RTCGET _IOR('p', 20, struct rtc_time)
-#define RTCSET _IOW('p', 21, struct rtc_time)
-
-#endif
diff --git a/arch/sparc/include/asm/sbus.h b/arch/sparc/include/asm/sbus.h
deleted file mode 100644 (file)
index f82481a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef ___ASM_SPARC_SBUS_H
-#define ___ASM_SPARC_SBUS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sbus_64.h>
-#else
-#include <asm/sbus_32.h>
-#endif
-#endif
diff --git a/arch/sparc/include/asm/sbus_32.h b/arch/sparc/include/asm/sbus_32.h
deleted file mode 100644 (file)
index a7b4fa2..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * sbus.h:  Defines for the Sun SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_SBUS_H
-#define _SPARC_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0xf8000000
-#define SBUS_OFF_MASK          0x01ffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<25)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>25);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-       struct of_device        ofdev;
-       struct sbus_bus         *bus;
-       struct sbus_dev         *next;
-       struct sbus_dev         *child;
-       struct sbus_dev         *parent;
-       int prom_node;
-       char prom_name[64];
-       int slot;
-
-       struct resource resource[PROMREG_MAX];
-
-       struct linux_prom_registers reg_addrs[PROMREG_MAX];
-       int num_registers;
-
-       struct linux_prom_ranges device_ranges[PROMREG_MAX];
-       int num_device_ranges;
-
-       unsigned int irqs[4];
-       int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-       struct of_device        ofdev;
-       struct sbus_dev         *devices;       /* Link to devices on this SBus */
-       struct sbus_bus         *next;          /* next SBus, if more than one SBus */
-       int                     prom_node;      /* PROM device tree node for this SBus */
-       char                    prom_name[64];  /* Usually "sbus" or "sbi" */
-       int                     clock_freq;
-
-       struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-       int num_sbus_ranges;
-
-       int devid;
-       int board;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-static inline int
-sbus_is_slave(struct sbus_dev *dev)
-{
-       /* XXX Have to write this for sun4c's */
-       return 0;
-}
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-       for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-               for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)       (0) /* actually, sparc_cpu_model==sun4d */
-#define sbus_can_burst64(sdev)         (0) /* actually, sparc_cpu_model==sun4d */
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-/* These yield IOMMU mappings in consistent mode. */
-extern void *sbus_alloc_consistent(struct sbus_dev *, long, u32 *dma_addrp);
-extern void sbus_free_consistent(struct sbus_dev *, long, void *, u32);
-void prom_adjust_ranges(struct linux_prom_ranges *, int,
-                       struct linux_prom_ranges *, int);
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE      DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE    DMA_FROM_DEVICE
-#define        SBUS_DMA_NONE           DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int);
-extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int);
-extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int);
-extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int);
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int);
-extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int);
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int);
-
-/* Eric Brower (ebrower@usa.net)
- * Translate SBus interrupt levels to ino values--
- * this is used when converting sbus "interrupts" OBP
- * node values to "intr" node values, and is platform
- * dependent.  If only we could call OBP with
- * "sbus-intr>cpu (sbint -- ino)" from kernel...
- * See .../drivers/sbus/sbus.c for details.
- */
-BTFIXUPDEF_CALL(unsigned int, sbint_to_irq, struct sbus_dev *sdev, unsigned int)
-#define sbint_to_irq(sdev, sbint) BTFIXUP_CALL(sbint_to_irq)(sdev, sbint)
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC_SBUS_H) */
diff --git a/arch/sparc/include/asm/sbus_64.h b/arch/sparc/include/asm/sbus_64.h
deleted file mode 100644 (file)
index b606c14..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/* sbus.h: Defines for the Sun SBus.
- *
- * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net)
- */
-
-#ifndef _SPARC64_SBUS_H
-#define _SPARC64_SBUS_H
-
-#include <linux/dma-mapping.h>
-#include <linux/ioport.h>
-#include <linux/of_device.h>
-
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/iommu.h>
-#include <asm/scatterlist.h>
-
-/* We scan which devices are on the SBus using the PROM node device
- * tree.  SBus devices are described in two different ways.  You can
- * either get an absolute address at which to access the device, or
- * you can get a SBus 'slot' number and an offset within that slot.
- */
-
-/* The base address at which to calculate device OBIO addresses. */
-#define SUN_SBUS_BVADDR        0x00000000
-#define SBUS_OFF_MASK          0x0fffffff
-
-/* These routines are used to calculate device address from slot
- * numbers + offsets, and vice versa.
- */
-
-static inline unsigned long sbus_devaddr(int slotnum, unsigned long offset)
-{
-  return (unsigned long) (SUN_SBUS_BVADDR+((slotnum)<<28)+(offset));
-}
-
-static inline int sbus_dev_slot(unsigned long dev_addr)
-{
-  return (int) (((dev_addr)-SUN_SBUS_BVADDR)>>28);
-}
-
-struct sbus_bus;
-
-/* Linux SBUS device tables */
-struct sbus_dev {
-       struct of_device        ofdev;
-       struct sbus_bus         *bus;
-       struct sbus_dev         *next;
-       struct sbus_dev         *child;
-       struct sbus_dev         *parent;
-       int prom_node;
-       char prom_name[64];
-       int slot;
-
-       struct resource resource[PROMREG_MAX];
-
-       struct linux_prom_registers reg_addrs[PROMREG_MAX];
-       int num_registers;
-
-       struct linux_prom_ranges device_ranges[PROMREG_MAX];
-       int num_device_ranges;
-
-       unsigned int irqs[4];
-       int num_irqs;
-};
-#define to_sbus_device(d) container_of(d, struct sbus_dev, ofdev.dev)
-
-/* This struct describes the SBus(s) found on this machine. */
-struct sbus_bus {
-       struct of_device        ofdev;
-       struct sbus_dev         *devices;       /* Tree of SBUS devices */
-       struct sbus_bus         *next;          /* Next SBUS in system  */
-       int                     prom_node;      /* OBP node of SBUS     */
-       char                    prom_name[64];  /* Usually "sbus" or "sbi" */
-       int                     clock_freq;
-
-       struct linux_prom_ranges sbus_ranges[PROMREG_MAX];
-       int num_sbus_ranges;
-
-       int portid;
-};
-#define to_sbus(d) container_of(d, struct sbus_bus, ofdev.dev)
-
-extern struct sbus_bus *sbus_root;
-
-/* Device probing routines could find these handy */
-#define for_each_sbus(bus) \
-        for((bus) = sbus_root; (bus); (bus)=(bus)->next)
-
-#define for_each_sbusdev(device, bus) \
-        for((device) = (bus)->devices; (device); (device)=(device)->next)
-
-#define for_all_sbusdev(device, bus) \
-       for ((bus) = sbus_root; (bus); (bus) = (bus)->next) \
-               for ((device) = (bus)->devices; (device); (device) = (device)->next)
-
-/* Driver DVMA interfaces. */
-#define sbus_can_dma_64bit(sdev)       (1)
-#define sbus_can_burst64(sdev)         (1)
-extern void sbus_set_sbus64(struct sbus_dev *, int);
-extern void sbus_fill_device_irq(struct sbus_dev *);
-
-static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size,
-                                         dma_addr_t *dma_handle)
-{
-       return dma_alloc_coherent(&sdev->ofdev.dev, size,
-                                 dma_handle, GFP_ATOMIC);
-}
-
-static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size,
-                                       void *vaddr, dma_addr_t dma_handle)
-{
-       return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle);
-}
-
-#define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL
-#define SBUS_DMA_TODEVICE      DMA_TO_DEVICE
-#define SBUS_DMA_FROMDEVICE    DMA_FROM_DEVICE
-#define        SBUS_DMA_NONE           DMA_NONE
-
-/* All the rest use streaming mode mappings. */
-static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr,
-                                        size_t size, int direction)
-{
-       return dma_map_single(&sdev->ofdev.dev, ptr, size,
-                             (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_single(struct sbus_dev *sdev,
-                                    dma_addr_t dma_addr, size_t size,
-                                    int direction)
-{
-       dma_unmap_single(&sdev->ofdev.dev, dma_addr, size,
-                        (enum dma_data_direction) direction);
-}
-
-static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-                             int nents, int direction)
-{
-       return dma_map_sg(&sdev->ofdev.dev, sg, nents,
-                         (enum dma_data_direction) direction);
-}
-
-static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg,
-                                int nents, int direction)
-{
-       dma_unmap_sg(&sdev->ofdev.dev, sg, nents,
-                    (enum dma_data_direction) direction);
-}
-
-/* Finally, allow explicit synchronization of streamable mappings. */
-static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev,
-                                               dma_addr_t dma_handle,
-                                               size_t size, int direction)
-{
-       dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size,
-                               (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu
-
-static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev,
-                                                  dma_addr_t dma_handle,
-                                                  size_t size, int direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev,
-                                           struct scatterlist *sg,
-                                           int nents, int direction)
-{
-       dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents,
-                           (enum dma_data_direction) direction);
-}
-#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu
-
-static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev,
-                                              struct scatterlist *sg,
-                                              int nents, int direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *);
-extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *);
-extern void sbus_setup_arch_props(struct sbus_bus *, struct device_node *);
-extern int sbus_arch_preinit(void);
-extern void sbus_arch_postinit(void);
-
-#endif /* !(_SPARC64_SBUS_H) */
index de2249b267c626bd0066a986afc2d910327a3dce..bf2d532593e3900ed9838fdf4334d0a2ae5b91db 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef __SPARC_SPINLOCK_H
 #define __SPARC_SPINLOCK_H
 
-#include <linux/threads.h>     /* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 #include <asm/psr.h>
index 0006fe9f8c7a03cab556cec5119ad5c016608e74..120cfe4577c752bc44a417cdf2e4c1cef986f1c9 100644 (file)
@@ -6,8 +6,6 @@
 #ifndef __SPARC64_SPINLOCK_H
 #define __SPARC64_SPINLOCK_H
 
-#include <linux/threads.h>     /* For NR_CPUS */
-
 #ifndef __ASSEMBLY__
 
 /* To get debugging spinlocks which detect and catch
diff --git a/arch/sparc/include/asm/sstate.h b/arch/sparc/include/asm/sstate.h
deleted file mode 100644 (file)
index a7c35db..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _SPARC64_SSTATE_H
-#define _SPARC64_SSTATE_H
-
-extern void sstate_booting(void);
-extern void sstate_running(void);
-extern void sstate_halt(void);
-extern void sstate_poweroff(void);
-extern void sstate_panic(void);
-extern void sstate_reboot(void);
-
-extern void sun4v_sstate_init(void);
-
-#endif /* _SPARC64_SSTATE_H */
index 07bafd31e33cd0f9a7d4dfc997202d84a6dd0c59..d56ce60a5992bc71f74694b05ed0858dfb8e7d36 100644 (file)
@@ -12,7 +12,6 @@
 extern int this_is_starfire;
 
 extern void check_if_starfire(void);
-extern void starfire_cpu_setup(void);
 extern int starfire_hard_smp_processor_id(void);
 extern void starfire_hookup(int);
 extern unsigned int starfire_translate(unsigned long imap, unsigned int upaid);
diff --git a/arch/sparc/include/asm/sun4paddr.h b/arch/sparc/include/asm/sun4paddr.h
deleted file mode 100644 (file)
index d52985f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * sun4paddr.h:  Various physical addresses on sun4 machines
- *
- * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
- * Copyright (C) 1998 Chris Davis (cdavis@cois.on.ca)
- * 
- * Now supports more sun4's
- */
-
-#ifndef _SPARC_SUN4PADDR_H
-#define _SPARC_SUN4PADDR_H
-
-#define SUN4_IE_PHYSADDR               0xf5000000
-#define SUN4_UNUSED_PHYSADDR           0
-
-/* these work for me */
-#define SUN4_200_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_200_CLOCK_PHYSADDR                0xf3000000
-#define SUN4_200_BWTWO_PHYSADDR                0xfd000000
-#define SUN4_200_ETH_PHYSADDR          0xf6000000
-#define SUN4_200_SI_PHYSADDR           0xff200000
-
-/* these were here before */
-#define SUN4_300_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_300_CLOCK_PHYSADDR                0xf2000000
-#define SUN4_300_TIMER_PHYSADDR                0xef000000
-#define SUN4_300_ETH_PHYSADDR          0xf9000000
-#define SUN4_300_BWTWO_PHYSADDR                0xfb400000
-#define SUN4_300_DMA_PHYSADDR          0xfa001000
-#define SUN4_300_ESP_PHYSADDR          0xfa000000
-
-/* Are these right? */
-#define SUN4_400_MEMREG_PHYSADDR       0xf4000000
-#define SUN4_400_CLOCK_PHYSADDR                0xf2000000
-#define SUN4_400_TIMER_PHYSADDR                0xef000000
-#define SUN4_400_ETH_PHYSADDR          0xf9000000
-#define SUN4_400_BWTWO_PHYSADDR                0xfb400000
-#define SUN4_400_DMA_PHYSADDR          0xfa001000
-#define SUN4_400_ESP_PHYSADDR          0xfa000000
-
-/* 
-       these are the actual values set and used in the code. Unused items set 
-       to SUN_UNUSED_PHYSADDR 
- */
-
-extern int sun4_memreg_physaddr; /* memory register (ecc?) */
-extern int sun4_clock_physaddr;  /* system clock */
-extern int sun4_timer_physaddr;  /* timer, where applicable */
-extern int sun4_eth_physaddr;    /* onboard ethernet (ie/le) */
-extern int sun4_si_physaddr;     /* sun3 scsi adapter */
-extern int sun4_bwtwo_physaddr;  /* onboard bw2 */
-extern int sun4_dma_physaddr;    /* scsi dma */
-extern int sun4_esp_physaddr;    /* esp scsi */
-extern int sun4_ie_physaddr;     /* interrupt enable */
-
-#endif /* !(_SPARC_SUN4PADDR_H) */
diff --git a/arch/sparc/include/asm/sun4prom.h b/arch/sparc/include/asm/sun4prom.h
deleted file mode 100644 (file)
index 9c8b4cb..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * sun4prom.h -- interface to sun4 PROM monitor.  We don't use most of this,
- *               so most of these are just placeholders.
- */
-
-#ifndef _SUN4PROM_H_
-#define _SUN4PROM_H_
-
-/*
- * Although this looks similar to an romvec for a OpenProm machine, it is 
- * actually closer to what was used in the Sun2 and Sun3.
- *
- * V2 entries exist only in version 2 PROMs and later, V3 in version 3 and later.
- * 
- * Many of the function prototypes are guesses.  Some are certainly wrong.
- * Use with care.
- */
-
-typedef struct {
-       char            *initSP;                /* Initial system stack ptr */
-       void            (*startmon)(void);      /* Initial PC for hardware */
-       int             *diagberr;              /* Bus err handler for diags */
-       struct linux_arguments_v0 **bootParam; /* Info for bootstrapped pgm */
-       unsigned int    *memorysize;            /* Usable memory in bytes */
-       unsigned char   (*getchar)(void);       /* Get char from input device */ 
-       void            (*putchar)(char);       /* Put char to output device */
-       int             (*mayget)(void);        /* Maybe get char, or -1 */
-       int             (*mayput)(int);         /* Maybe put char, or -1 */
-       unsigned char   *echo;                  /* Should getchar echo? */
-       unsigned char   *insource;              /* Input source selector */
-       unsigned char   *outsink;               /* Output sink selector */
-       int             (*getkey)(void);        /* Get next key if one exists */
-       void            (*initgetkey)(void);    /* Initialize get key */
-       unsigned int    *translation;           /* Kbd translation selector */
-       unsigned char   *keybid;                /* Keyboard ID byte */
-       int             *screen_x;              /* V2: Screen x pos (r/o) */
-       int             *screen_y;              /* V2: Screen y pos (r/o) */
-       struct keybuf   *keybuf;                /* Up/down keycode buffer */
-       char            *monid;                 /* Monitor version ID */
-       void            (*fbwritechar)(char);   /* Write a character to FB */
-       int             *fbAddr;                /* Address of frame buffer */
-       char            **font;                 /* Font table for FB */
-       void            (*fbwritestr)(char *);  /* Write string to FB */
-       void            (*reboot)(char *);      /* e.g. reboot("sd()vmlinux") */
-       unsigned char   *linebuf;               /* The line input buffer */
-       unsigned char   **lineptr;              /* Cur pointer into linebuf */
-       int             *linesize;              /* length of line in linebuf */
-       void            (*getline)(char *);     /* Get line from user */
-       unsigned char   (*getnextchar)(void);   /* Get next char from linebuf */
-       unsigned char   (*peeknextchar)(void);  /* Peek at next char */
-       int             *fbthere;               /* =1 if frame buffer there */
-       int             (*getnum)(void);        /* Grab hex num from line */
-       int             (*printf)(char *, ...); /* See prom_printf() instead */ 
-       void            (*printhex)(int);       /* Format N digits in hex */
-       unsigned char   *leds;                  /* RAM copy of LED register */
-       void            (*setLEDs)(unsigned char *);    /* Sets LED's and RAM copy */
-       void            (*NMIaddr)(void *);     /* Addr for level 7 vector */
-       void            (*abortentry)(void);    /* Entry for keyboard abort */
-       int             *nmiclock;              /* Counts up in msec */
-       int             *FBtype;                /* Frame buffer type */
-       unsigned int    romvecversion;          /* Version number for this romvec */
-       struct globram  *globram;               /* monitor global variables ??? */
-       void *          kbdaddr;                /* Addr of keyboard in use */
-       int             *keyrinit;              /* ms before kbd repeat */
-       unsigned char   *keyrtick;              /* ms between repetitions */
-       unsigned int    *memoryavail;           /* V1: Main mem usable size */
-       long            *resetaddr;             /* where to jump on a reset */
-       long            *resetmap;              /* pgmap entry for resetaddr */
-       void            (*exittomon)(void);     /* Exit from user program */
-       unsigned char   **memorybitmap;         /* V1: &{0 or &bits} */
-       void            (*setcxsegmap)(int ctxt, char *va, int pmeg);   /* Set seg in any context */
-       void            (**vector_cmd)(void *); /* V2: Handler for 'v' cmd */
-       unsigned long   *expectedtrapsig;       /* V3: Location of the expected trap signal */
-       unsigned long   *trapvectorbasetable;   /* V3: Address of the trap vector table */
-       int             unused1;
-       int             unused2;
-       int             unused3;
-       int             unused4;
-} linux_sun4_romvec;
-
-extern linux_sun4_romvec *sun4_romvec;
-
-#endif /* _SUN4PROM_H_ */
index b4b024445fc984f0d419f5f997690b83a8efd733..8623fc48fe247bbe4005bb3400d34802cff70fa1 100644 (file)
@@ -34,13 +34,7 @@ enum sparc_cpu {
 
 extern enum sparc_cpu sparc_cpu_model;
 
-#ifndef CONFIG_SUN4
-#define ARCH_SUN4C_SUN4 (sparc_cpu_model==sun4c)
-#define ARCH_SUN4 0
-#else
-#define ARCH_SUN4C_SUN4 1
-#define ARCH_SUN4 1
-#endif
+#define ARCH_SUN4C (sparc_cpu_model==sun4c)
 
 #define SUN4M_NCPUS            4              /* Architectural limit of sun4m. */
 
@@ -55,6 +49,7 @@ extern unsigned long empty_zero_page;
 extern void sun_do_break(void);
 extern int serial_console;
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 static inline int con_is_present(void)
 {
index db9e742a406ae6a9d08e8c322d2bef9eec9b3e61..8759f2a1b837c3f4c655cf48d10b91475f54da12 100644 (file)
@@ -26,9 +26,8 @@ enum sparc_cpu {
 
 #define sparc_cpu_model sun4u
 
-/* This cannot ever be a sun4c nor sun4 :) That's just history. */
-#define ARCH_SUN4C_SUN4 0
-#define ARCH_SUN4 0
+/* This cannot ever be a sun4c :) That's just history. */
+#define ARCH_SUN4C 0
 
 extern char reboot_command[];
 
@@ -118,6 +117,7 @@ do {        __asm__ __volatile__("ba,pt     %%xcc, 1f\n\t" \
 
 extern void sun_do_break(void);
 extern int stop_a_enabled;
+extern int scons_pwroff;
 
 extern void fault_in_user_windows(void);
 extern void synchronize_user_stack(void);
index cbb892d0dff04b033ae371af6175cb443cb2c06e..29899fd5b1b228236d3f495c35e16ed511b57cb4 100644 (file)
@@ -80,11 +80,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
 /*
  * thread information allocation
  */
-#if PAGE_SHIFT == 13
-#define THREAD_INFO_ORDER  0
-#else /* PAGE_SHIFT */
 #define THREAD_INFO_ORDER  1
-#endif
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
index 361e53898dd7b298e0fa2c41683437a671e15b9c..2ec030ef38102307911b405ce62e04c3e4470152 100644 (file)
@@ -9,96 +9,9 @@
 #define _SPARC_TIMER_H
 
 #include <asm/system.h>  /* For SUN4M_NCPUS */
-#include <asm/sun4paddr.h>
 #include <asm/btfixup.h>
 
-/* Timer structures. The interrupt timer has two properties which
- * are the counter (which is handled in do_timer in sched.c) and the limit.
- * This limit is where the timer's counter 'wraps' around. Oddly enough,
- * the sun4c timer when it hits the limit wraps back to 1 and not zero
- * thus when calculating the value at which it will fire a microsecond you
- * must adjust by one.  Thanks SUN for designing such great hardware ;(
- */
-
-/* Note that I am only going to use the timer that interrupts at
- * Sparc IRQ 10.  There is another one available that can fire at
- * IRQ 14. Currently it is left untouched, we keep the PROM's limit
- * register value and let the prom take these interrupts.  This allows
- * L1-A to work.
- */
-
-struct sun4c_timer_info {
-  __volatile__ unsigned int cur_count10;
-  __volatile__ unsigned int timer_limit10;
-  __volatile__ unsigned int cur_count14;
-  __volatile__ unsigned int timer_limit14;
-};
-
-#define SUN4C_TIMER_PHYSADDR   0xf3000000
-#ifdef CONFIG_SUN4
-#define SUN_TIMER_PHYSADDR SUN4_300_TIMER_PHYSADDR
-#else
-#define SUN_TIMER_PHYSADDR SUN4C_TIMER_PHYSADDR
-#endif
-
-/* A sun4m has two blocks of registers which are probably of the same
- * structure. LSI Logic's L64851 is told to _decrement_ from the limit
- * value. Aurora behaves similarly but its limit value is compacted in
- * other fashion (it's wider). Documented fields are defined here.
- */
-
-/* As with the interrupt register, we have two classes of timer registers
- * which are per-cpu and master.  Per-cpu timers only hit that cpu and are
- * only level 14 ticks, master timer hits all cpus and is level 10.
- */
-
-#define SUN4M_PRM_CNT_L       0x80000000
-#define SUN4M_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4m_timer_percpu_info {
-  __volatile__ unsigned int l14_timer_limit;    /* Initial value is 0x009c4000 */
-  __volatile__ unsigned int l14_cur_count;
-
-  /* This register appears to be write only and/or inaccessible
-   * on Uni-Processor sun4m machines.
-   */
-  __volatile__ unsigned int l14_limit_noclear;  /* Data access error is here */
-
-  __volatile__ unsigned int cntrl;            /* =1 after POST on Aurora */
-  __volatile__ unsigned char space[PAGE_SIZE - 16];
-};
-
-struct sun4m_timer_regs {
-       struct sun4m_timer_percpu_info cpu_timers[SUN4M_NCPUS];
-       volatile unsigned int l10_timer_limit;
-       volatile unsigned int l10_cur_count;
-
-       /* Again, this appears to be write only and/or inaccessible
-        * on uni-processor sun4m machines.
-        */
-       volatile unsigned int l10_limit_noclear;
-
-       /* This register too, it must be magic. */
-       volatile unsigned int foobar;
-
-       volatile unsigned int cfg;     /* equals zero at boot time... */
-};
-
-#define SUN4D_PRM_CNT_L       0x80000000
-#define SUN4D_PRM_CNT_LVALUE  0x7FFFFC00
-
-struct sun4d_timer_regs {
-       volatile unsigned int l10_timer_limit;
-       volatile unsigned int l10_cur_countx;
-       volatile unsigned int l10_limit_noclear;
-       volatile unsigned int ctrl;
-       volatile unsigned int l10_cur_count;
-};
-
-extern struct sun4d_timer_regs *sun4d_timers;
-
 extern __volatile__ unsigned int *master_l10_counter;
-extern __volatile__ unsigned int *master_l10_limit;
 
 /* FIXME: Make do_[gs]ettimeofday btfixup calls */
 BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv)
index d10527611f11a967f2630dac077ebd4b7a14d53b..a63e88ef0426479950525f2054510583129372f4 100644 (file)
  * cacheable bit in the pte's of all such pages.
  */
 
-#ifdef CONFIG_SUN4
-#define S4CVAC_BADBITS     0x0001e000
-#else
 #define S4CVAC_BADBITS    0x0000f000
-#endif
 
 /* The following is true if vaddr1 and vaddr2 would cause
  * a 'bad alias'.
  */
 struct sun4c_vac_props {
        unsigned int num_bytes;     /* Size of the cache */
-       unsigned int num_lines;     /* Number of cache lines */
        unsigned int do_hwflushes;  /* Hardware flushing available? */
-       enum { VAC_NONE, VAC_WRITE_THROUGH,
-           VAC_WRITE_BACK } type;  /* What type of VAC? */
        unsigned int linesize;      /* Size of each line in bytes */
        unsigned int log2lsize;     /* log2(linesize) */
        unsigned int on;            /* VAC is enabled */
diff --git a/arch/sparc/include/asm/vfc_ioctls.h b/arch/sparc/include/asm/vfc_ioctls.h
deleted file mode 100644 (file)
index af8b690..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (c) 1996 by Manish Vachharajani */
-
-#ifndef _LINUX_VFC_IOCTLS_H_
-#define        _LINUX_VFC_IOCTLS_H_
-
-       /* IOCTLs */
-#define VFC_IOCTL(a)          (('j' << 8) | a)
-#define VFCGCTRL       (VFC_IOCTL (0))         /* get vfc attributes */
-#define VFCSCTRL       (VFC_IOCTL (1))         /* set vfc attributes */
-#define VFCGVID                (VFC_IOCTL (2))         /* get video decoder attributes */
-#define VFCSVID                (VFC_IOCTL (3))         /* set video decoder attributes */
-#define VFCHUE         (VFC_IOCTL (4))         /* set hue */
-#define VFCPORTCHG     (VFC_IOCTL (5))         /* change port */
-#define VFCRDINFO      (VFC_IOCTL (6))         /* read info */
-
-       /* Options for setting the vfc attributes and status */
-#define MEMPRST                0x1     /* reset FIFO ptr. */
-#define CAPTRCMD       0x2     /* start capture and wait */
-#define DIAGMODE       0x3     /* diag mode */
-#define NORMMODE       0x4     /* normal mode */
-#define CAPTRSTR       0x5     /* start capture */
-#define CAPTRWAIT      0x6     /* wait for capture to finish */
-
-
-       /* Options for the decoder */
-#define STD_NTSC       0x1     /* NTSC mode */
-#define STD_PAL                0x2     /* PAL mode */
-#define COLOR_ON       0x3     /* force color ON */
-#define MONO           0x4     /* force color OFF */
-
-       /* Values returned by ioctl 2 */
-
-#define NO_LOCK                1
-#define NTSC_COLOR     2
-#define NTSC_NOCOLOR    3
-#define PAL_COLOR      4
-#define PAL_NOCOLOR    5
-
-/* Not too sure what this does yet */
-       /* Options for setting Field number */
-#define ODD_FIELD      0x1
-#define EVEN_FIELD     0x0
-#define ACTIVE_ONLY     0x2
-#define NON_ACTIVE     0x0
-
-/* Debug options */
-#define VFC_I2C_SEND 0
-#define VFC_I2C_RECV 1
-
-struct vfc_debug_inout
-{
-       unsigned long addr;
-       unsigned long ret;
-       unsigned long len;
-       unsigned char __user *buffer;
-};
-
-#endif /* _LINUX_VFC_IOCTLS_H_ */
index de797b9bf5525a020dfdbb3a6cf3afbb42407811..39ca301920db72ec44be555ec80a167ccdc2cdb4 100644 (file)
@@ -57,6 +57,7 @@ static inline void save_and_clear_fpu(void) {
 "              " : : "i" (FPRS_FEF|FPRS_DU) :
                "o5", "g1", "g2", "g3", "g7", "cc");
 }
+extern int vis_emul(struct pt_regs *, unsigned int);
 #endif
 
 #endif /* _SPARC64_ASI_H */
index 6e03a2a7863c77e4a999a449b6e28968a75e9de7..2d658209509943ce5d29fd0d6ebd2553097d4d76 100644 (file)
@@ -13,15 +13,13 @@ obj-y    := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
            time.o windows.o cpu.o devices.o \
            tadpole.o tick14.o ptrace.o \
            unaligned.o una_asm.o muldiv.o \
-           prom.o of_device.o devres.o
+           prom.o of_device.o devres.o dma.o
 
 devres-y = ../../../kernel/irq/devres.o
 
 obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SUN4) += sun4setup.o
 obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
 obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_PCI) += ebus.o
 obj-$(CONFIG_SUN_PM) += apc.o pmc.o
 obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
 obj-$(CONFIG_SPARC_LED) += led.o
index 5267d48fb2c6a36e5a777f4b51041c58944d95bc..4dd1ba752ce6338376df2f7fd4bb297195ec251a 100644 (file)
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
 #define APC_OBPNAME    "power-management"
 #define APC_DEVNAME "apc"
 
-volatile static u8 __iomem *regs; 
-static int apc_regsize;
+static u8 __iomem *regs;
 static int apc_no_idle __initdata = 0;
 
-#define apc_readb(offs)                        (sbus_readb(regs+offs))
+#define apc_readb(offs)                (sbus_readb(regs+offs))
 #define apc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
 
 /* Specify "apc=noidle" on the kernel command line to 
@@ -69,9 +69,9 @@ static void apc_swift_idle(void)
 #endif
 } 
 
-static inline void apc_free(void)
+static inline void apc_free(struct of_device *op)
 {
-       sbus_iounmap(regs, apc_regsize);
+       of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0]));
 }
 
 static int apc_open(struct inode *inode, struct file *f)
@@ -153,52 +153,56 @@ static const struct file_operations apc_fops = {
 
 static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops };
 
-static int __init apc_probe(void)
+static int __devinit apc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       struct sbus_bus *sbus = NULL;
-       struct sbus_dev *sdev = NULL;
-       int iTmp = 0;
-
-       for_each_sbus(sbus) {
-               for_each_sbusdev(sdev, sbus) {
-                       if (!strcmp(sdev->prom_name, APC_OBPNAME)) {
-                               goto sbus_done;
-                       }
-               }
-       }
+       int err;
 
-sbus_done:
-       if (!sdev) {
-               return -ENODEV;
-       }
-
-       apc_regsize = sdev->reg_addrs[0].reg_size;
-       regs = sbus_ioremap(&sdev->resource[0], 0, 
-                                  apc_regsize, APC_OBPNAME);
-       if(!regs) {
+       regs = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]), APC_OBPNAME);
+       if (!regs) {
                printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME);
                return -ENODEV;
        }
 
-       iTmp = misc_register(&apc_miscdev);
-       if (iTmp != 0) {
+       err = misc_register(&apc_miscdev);
+       if (err) {
                printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME);
-               apc_free();
+               apc_free(op);
                return -ENODEV;
        }
 
        /* Assign power management IDLE handler */
-       if(!apc_no_idle)
+       if (!apc_no_idle)
                pm_idle = apc_swift_idle;       
 
        printk(KERN_INFO "%s: power management initialized%s\n", 
-               APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+              APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : "");
+
        return 0;
 }
 
+static struct of_device_id __initdata apc_match[] = {
+       {
+               .name = APC_OBPNAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, apc_match);
+
+static struct of_platform_driver apc_driver = {
+       .name           = "apc",
+       .match_table    = apc_match,
+       .probe          = apc_probe,
+};
+
+static int __init apc_init(void)
+{
+       return of_register_driver(&apc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(apc_probe);
-
+__initcall(apc_init);
index baf4ed3fb0f3d116f6966c48a93a6b7551884bc0..09c857215a52fad2e2229ac6c86739eee4a6789b 100644 (file)
@@ -6,6 +6,8 @@
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
 #include <asm/io.h>
 #include <asm/auxio.h>
@@ -59,7 +61,7 @@ void __init auxio_probe(void)
        r.flags = auxregs[0].which_io & 0xF;
        r.start = auxregs[0].phys_addr;
        r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1;
-       auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
+       auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio");
        /* Fix the address on sun4m and sun4c. */
        if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 ||
           sparc_cpu_model == sun4c)
@@ -128,7 +130,7 @@ void __init auxio_power_probe(void)
        r.flags = regs.which_io & 0xF;
        r.start = regs.phys_addr;
        r.end = regs.phys_addr + regs.reg_size - 1;
-       auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0,
+       auxio_power_register = (unsigned char *) of_ioremap(&r, 0,
            regs.reg_size, "auxpower");
 
        /* Display a quick message on the console. */
index b240b8863fd044153319340f3960fa87e88cd6ba..ad656b044b8c2b9a560af4cdfaf2a05e65634f2a 100644 (file)
@@ -143,7 +143,7 @@ void __init device_scan(void)
 #endif
        clock_stop_probe();
 
-       if (ARCH_SUN4C_SUN4)
+       if (ARCH_SUN4C)
                sun4c_probe_memerr_reg();
 
        return;
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c
new file mode 100644 (file)
index 0000000..ebc8403
--- /dev/null
@@ -0,0 +1,227 @@
+/* dma.c: PCI and SBUS DMA accessors for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include "dma.h"
+
+int dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_dma_supported(to_pci_dev(dev), mask);
+#endif
+       return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+                        dma_addr_t *dma_handle, gfp_t flag)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle);
+#endif
+       return sbus_alloc_consistent(dev, size, dma_handle);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size,
+                      void *cpu_addr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_free_consistent(to_pci_dev(dev), size,
+                                   cpu_addr, dma_handle);
+               return;
+       }
+#endif
+       sbus_free_consistent(dev, size, cpu_addr, dma_handle);
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                         size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_single(to_pci_dev(dev), cpu_addr,
+                                     size, (int)direction);
+#endif
+       return sbus_map_single(dev, cpu_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                     size_t size,
+                     enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_single(to_pci_dev(dev), dma_addr,
+                                size, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_single(dev, dma_addr, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                       unsigned long offset, size_t size,
+                       enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_page(to_pci_dev(dev), page, offset,
+                                   size, (int)direction);
+#endif
+       return sbus_map_single(dev, page_address(page) + offset,
+                              size, (int)direction);
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                   size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_page(to_pci_dev(dev), dma_address,
+                              size, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_single(dev, dma_address, size, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                            int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type)
+               return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction);
+#endif
+       return sbus_map_sg(dev, sg, nents, direction);
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                 int nents, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction);
+               return;
+       }
+#endif
+       sbus_unmap_sg(dev, sg, nents, (int)direction);
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                            size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle,
+                                           size, (int)direction);
+               return;
+       }
+#endif
+       sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+                               size_t size, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle,
+                                              size, (int)direction);
+               return;
+       }
+#endif
+       sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev,
+                                  dma_addr_t dma_handle,
+                                  unsigned long offset,
+                                  size_t size,
+                                  enum dma_data_direction direction)
+{
+       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction direction)
+{
+       dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                        int nelems, enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg,
+                                       nelems, (int)direction);
+               return;
+       }
+#endif
+       BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev,
+                           struct scatterlist *sg, int nelems,
+                           enum dma_data_direction direction)
+{
+#ifdef CONFIG_PCI
+       if (dev->bus == &pci_bus_type) {
+               pci_dma_sync_sg_for_device(to_pci_dev(dev), sg,
+                                          nelems, (int)direction);
+               return;
+       }
+#endif
+       BUG();
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return (dma_addr == DMA_ERROR_CODE);
+}
+EXPORT_SYMBOL(dma_mapping_error);
+
+int dma_get_cache_alignment(void)
+{
+       return 32;
+}
+EXPORT_SYMBOL(dma_get_cache_alignment);
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h
new file mode 100644 (file)
index 0000000..f8d8951
--- /dev/null
@@ -0,0 +1,14 @@
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp);
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba);
+dma_addr_t sbus_map_single(struct device *dev, void *va,
+                          size_t len, int direction);
+void sbus_unmap_single(struct device *dev, dma_addr_t ba,
+                      size_t n, int direction);
+int sbus_map_sg(struct device *dev, struct scatterlist *sg,
+               int n, int direction);
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg,
+                  int n, int direction);
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
+                                 size_t size, int direction);
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba,
+                                    size_t size, int direction);
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
deleted file mode 100644 (file)
index 9729423..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * ebus.c: PCI to EBus bridge device.
- *
- * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
- *
- * Adopted for sparc by V. Roganov and G. Raiko.
- * Fixes for different platforms by Pete Zaitcev.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pbm.h>
-#include <asm/ebus.h>
-#include <asm/io.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-
-struct linux_ebus *ebus_chain = NULL;
-
-/* We are together with pcic.c under CONFIG_PCI. */
-extern unsigned int pcic_pin_to_irq(unsigned int, const char *name);
-
-/*
- * IRQ Blacklist
- * Here we list PROMs and systems that are known to supply crap as IRQ numbers.
- */
-struct ebus_device_irq {
-       char *name;
-       unsigned int pin;
-};
-
-struct ebus_system_entry {
-       char *esname;
-       struct ebus_device_irq *ipt;
-};
-
-static struct ebus_device_irq je1_1[] = {
-       { "8042",                3 },
-       { "SUNW,CS4231",         0 },
-       { "parallel",            0 },
-       { "se",                  2 },
-       { NULL, 0 }
-};
-
-/*
- * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32).
- * Blacklist the sucker... Note that Gleb's system will work.
- */
-static struct ebus_system_entry ebus_blacklist[] = {
-       { "SUNW,JavaEngine1", je1_1 },
-       { NULL, NULL }
-};
-
-static struct ebus_device_irq *ebus_blackp = NULL;
-
-/*
- */
-static inline unsigned long ebus_alloc(size_t size)
-{
-       return (unsigned long)kmalloc(size, GFP_ATOMIC);
-}
-
-/*
- */
-static int __init ebus_blacklist_irq(const char *name)
-{
-       struct ebus_device_irq *dp;
-
-       if ((dp = ebus_blackp) != NULL) {
-               for (; dp->name != NULL; dp++) {
-                       if (strcmp(name, dp->name) == 0) {
-                               return pcic_pin_to_irq(dp->pin, name);
-                       }
-               }
-       }
-       return 0;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-                                  struct linux_ebus_child *dev)
-{
-       const int *regs;
-       const int *irqs;
-       int i, len;
-
-       dev->prom_node = dp;
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               len = 0;
-       dev->num_addrs = len / sizeof(regs[0]);
-
-       for (i = 0; i < dev->num_addrs; i++) {
-               if (regs[i] >= dev->parent->num_addrs) {
-                       prom_printf("UGH: property for %s was %d, need < %d\n",
-                                   dev->prom_node->name, len,
-                                   dev->parent->num_addrs);
-                       panic(__func__);
-               }
-
-               /* XXX resource */
-               dev->resource[i].start =
-                       dev->parent->resource[regs[i]].start;
-       }
-
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
-
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-               dev->num_irqs = 1;
-       } else {
-               irqs = of_get_property(dp, "interrupts", &len);
-               if (!irqs) {
-                       dev->num_irqs = 0;
-                       dev->irqs[0] = 0;
-                       if (dev->parent->num_irqs != 0) {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[0];
-                       }
-               } else {
-                       dev->num_irqs = len / sizeof(irqs[0]);
-                       if (irqs[0] == 0 || irqs[0] >= 8) {
-                               /*
-                                * XXX Zero is a valid pin number...
-                                * This works as long as Ebus is not wired
-                                * to INTA#.
-                                */
-                               printk("EBUS: %s got bad irq %d from PROM\n",
-                                      dev->prom_node->name, irqs[0]);
-                               dev->num_irqs = 0;
-                               dev->irqs[0] = 0;
-                       } else {
-                               dev->irqs[0] =
-                                       pcic_pin_to_irq(irqs[0],
-                                                       dev->prom_node->name);
-                       }
-               }
-       }
-}
-
-static void __init fill_ebus_device(struct device_node *dp,
-                                   struct linux_ebus_device *dev)
-{
-       const struct linux_prom_registers *regs;
-       struct linux_ebus_child *child;
-       struct dev_archdata *sd;
-       const int *irqs;
-       int i, n, len;
-       unsigned long baseaddr;
-
-       dev->prom_node = dp;
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               len = 0;
-       if (len % sizeof(struct linux_prom_registers)) {
-               prom_printf("UGH: proplen for %s was %d, need multiple of %d\n",
-                           dev->prom_node->name, len,
-                           (int)sizeof(struct linux_prom_registers));
-               panic(__func__);
-       }
-       dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-       for (i = 0; i < dev->num_addrs; i++) {
-               /*
-                * XXX Collect JE-1 PROM
-                * 
-                * Example - JS-E with 3.11:
-                *  /ebus
-                *      regs 
-                *        0x00000000, 0x0, 0x00000000, 0x0, 0x00000000,
-                *        0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000,
-                *        0x82000014, 0x0, 0x38800000, 0x0, 0x00800000,
-                *      ranges
-                *        0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000,
-                *        0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000,
-                *  /ebus/8042
-                *      regs
-                *        0x00000001, 0x00300060, 0x00000008,
-                *        0x00000001, 0x00300060, 0x00000008,
-                */
-               n = regs[i].which_io;
-               if (n >= 4) {
-                       /* XXX This is copied from old JE-1 by Gleb. */
-                       n = (regs[i].which_io - 0x10) >> 2;
-               } else {
-                       ;
-               }
-
-/*
- * XXX Now as we have regions, why don't we make an on-demand allocation...
- */
-               dev->resource[i].start = 0;
-               if ((baseaddr = dev->bus->self->resource[n].start +
-                   regs[i].phys_addr) != 0) {
-                       /* dev->resource[i].name = dev->prom_name; */
-                       if ((baseaddr = (unsigned long) ioremap(baseaddr,
-                           regs[i].reg_size)) == 0) {
-                               panic("ebus: unable to remap dev %s",
-                                     dev->prom_node->name);
-                       }
-               }
-               dev->resource[i].start = baseaddr;      /* XXX Unaligned */
-       }
-
-       for (i = 0; i < PROMINTR_MAX; i++)
-               dev->irqs[i] = PCI_IRQ_NONE;
-
-       if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) {
-               dev->num_irqs = 1;
-       } else {
-               irqs = of_get_property(dp, "interrupts", &len);
-               if (!irqs) {
-                       dev->num_irqs = 0;
-                       if ((dev->irqs[0] = dev->bus->self->irq) != 0) {
-                               dev->num_irqs = 1;
-/* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */
-                       }
-               } else {
-                       dev->num_irqs = 1;  /* dev->num_irqs = len / sizeof(irqs[0]); */
-                       if (irqs[0] == 0 || irqs[0] >= 8) {
-                               /* See above for the parent. XXX */
-                               printk("EBUS: %s got bad irq %d from PROM\n",
-                                      dev->prom_node->name, irqs[0]);
-                               dev->num_irqs = 0;
-                               dev->irqs[0] = 0;
-                       } else {
-                               dev->irqs[0] =
-                                       pcic_pin_to_irq(irqs[0],
-                                                       dev->prom_node->name);
-                       }
-               }
-       }
-
-       sd = &dev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &dev->ofdev;
-       sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-
-       dev->ofdev.node = dp;
-       dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-       dev->ofdev.dev.bus = &ebus_bus_type;
-       sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node);
-
-       /* Register with core */
-       if (of_device_register(&dev->ofdev) != 0)
-               printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       if ((dp = dp->child) != NULL) {
-               dev->children = (struct linux_ebus_child *)
-                       ebus_alloc(sizeof(struct linux_ebus_child));
-
-               child = dev->children;
-               child->next = NULL;
-               child->parent = dev;
-               child->bus = dev->bus;
-               fill_ebus_child(dp, child);
-
-               while ((dp = dp->sibling) != NULL) {
-                       child->next = (struct linux_ebus_child *)
-                               ebus_alloc(sizeof(struct linux_ebus_child));
-
-                       child = child->next;
-                       child->next = NULL;
-                       child->parent = dev;
-                       child->bus = dev->bus;
-                       fill_ebus_child(dp, child);
-               }
-       }
-}
-
-void __init ebus_init(void)
-{
-       const struct linux_prom_pci_registers *regs;
-       struct linux_pbm_info *pbm;
-       struct linux_ebus_device *dev;
-       struct linux_ebus *ebus;
-       struct ebus_system_entry *sp;
-       struct pci_dev *pdev;
-       struct pcidev_cookie *cookie;
-       struct device_node *dp;
-       struct resource *p;
-       unsigned short pci_command;
-       int len, reg, nreg;
-       int num_ebus = 0;
-
-       dp = of_find_node_by_path("/");
-       for (sp = ebus_blacklist; sp->esname != NULL; sp++) {
-               if (strcmp(dp->name, sp->esname) == 0) {
-                       ebus_blackp = sp->ipt;
-                       break;
-               }
-       }
-
-       pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL);
-       if (!pdev)
-               return;
-
-       cookie = pdev->sysdata;
-       dp = cookie->prom_node;
-
-       ebus_chain = ebus = (struct linux_ebus *)
-                       ebus_alloc(sizeof(struct linux_ebus));
-       ebus->next = NULL;
-
-       while (dp) {
-               struct device_node *nd;
-
-               ebus->prom_node = dp;
-               ebus->self = pdev;
-               ebus->parent = pbm = cookie->pbm;
-
-               /* Enable BUS Master. */
-               pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-               pci_command |= PCI_COMMAND_MASTER;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_command);
-
-               regs = of_get_property(dp, "reg", &len);
-               if (!regs) {
-                       prom_printf("%s: can't find reg property\n",
-                                   __func__);
-                       prom_halt();
-               }
-               nreg = len / sizeof(struct linux_prom_pci_registers);
-
-               p = &ebus->self->resource[0];
-               for (reg = 0; reg < nreg; reg++) {
-                       if (!(regs[reg].which_io & 0x03000000))
-                               continue;
-
-                       (p++)->start = regs[reg].phys_lo;
-               }
-
-               ebus->ofdev.node = dp;
-               ebus->ofdev.dev.parent = &pdev->dev;
-               ebus->ofdev.dev.bus = &ebus_bus_type;
-               sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus);
-
-               /* Register with core */
-               if (of_device_register(&ebus->ofdev) != 0)
-                       printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                              dp->path_component_name);
-
-
-               nd = dp->child;
-               if (!nd)
-                       goto next_ebus;
-
-               ebus->devices = (struct linux_ebus_device *)
-                               ebus_alloc(sizeof(struct linux_ebus_device));
-
-               dev = ebus->devices;
-               dev->next = NULL;
-               dev->children = NULL;
-               dev->bus = ebus;
-               fill_ebus_device(nd, dev);
-
-               while ((nd = nd->sibling) != NULL) {
-                       dev->next = (struct linux_ebus_device *)
-                               ebus_alloc(sizeof(struct linux_ebus_device));
-
-                       dev = dev->next;
-                       dev->next = NULL;
-                       dev->children = NULL;
-                       dev->bus = ebus;
-                       fill_ebus_device(nd, dev);
-               }
-
-       next_ebus:
-               pdev = pci_get_device(PCI_VENDOR_ID_SUN,
-                                      PCI_DEVICE_ID_SUN_EBUS, pdev);
-               if (!pdev)
-                       break;
-
-               cookie = pdev->sysdata;
-               dp = cookie->prom_node;
-
-               ebus->next = (struct linux_ebus *)
-                       ebus_alloc(sizeof(struct linux_ebus));
-               ebus = ebus->next;
-               ebus->next = NULL;
-               ++num_ebus;
-       }
-       if (pdev)
-               pci_dev_put(pdev);
-}
index e8cdf715a546ccb0af9b0802d249368470a5a119..faf9ccd9ef5dfc32f41da7c3b9b1d74f564669bc 100644 (file)
 #include <asm/memreg.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
-#ifdef CONFIG_SUN4
-#include <asm/pgtsun4.h>
-#else
 #include <asm/pgtsun4c.h>
-#endif
 #include <asm/winmacro.h>
 #include <asm/signal.h>
 #include <asm/obio.h>
@@ -276,17 +272,18 @@ smp4m_ticker:
         */
 maybe_smp4m_msg:
        GET_PROCESSOR4M_ID(o3)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
+       sethi   %hi(sun4m_irq_percpu), %l5
+       sll     %o3, 2, %o3
+       or      %l5, %lo(sun4m_irq_percpu), %o5
        sethi   %hi(0x40000000), %o2
-       sll     %o3, 12, %o3
        ld      [%o5 + %o3], %o1
-       andcc   %o1, %o2, %g0
+       ld      [%o1 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
+       andcc   %o3, %o2, %g0
        be,a    smp4m_ticker
         cmp    %l7, 14
-       st      %o2, [%o5 + 0x4]
+       st      %o2, [%o1 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x40000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o1 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -304,16 +301,16 @@ linux_trap_ipi15_sun4m:
        SAVE_ALL
        sethi   %hi(0x80000000), %o2
        GET_PROCESSOR4M_ID(o0)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
-       sll     %o0, 12, %o0
-       add     %o5, %o0, %o5
-       ld      [%o5], %o3
+       sethi   %hi(sun4m_irq_percpu), %l5
+       or      %l5, %lo(sun4m_irq_percpu), %o5
+       sll     %o0, 2, %o0
+       ld      [%o5 + %o0], %o5
+       ld      [%o5 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
        andcc   %o3, %o2, %g0
        be      1f                      ! Must be an NMI async memory error
-        st     %o2, [%o5 + 4]
+        st     %o2, [%o5 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x80000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o5 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -327,12 +324,11 @@ linux_trap_ipi15_sun4m:
 1:
        /* NMI async memory error handling. */
        sethi   %hi(0x80000000), %l4
-       sethi   %hi(0x4000), %o3
-       sub     %o5, %o0, %o5
-       add     %o5, %o3, %l5
-       st      %l4, [%l5 + 0xc]
+       sethi   %hi(sun4m_irq_global), %o5
+       ld      [%o5 + %lo(sun4m_irq_global)], %l5
+       st      %l4, [%l5 + 0x0c]       ! sun4m_irq_global->mask_set=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -341,9 +337,9 @@ linux_trap_ipi15_sun4m:
        WRITE_PAUSE
        call    sun4m_nmi
         nop
-       st      %l4, [%l5 + 0x8]
+       st      %l4, [%l5 + 0x08]       ! sun4m_irq_global->mask_clear=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        RESTORE_ALL
 
@@ -775,11 +771,7 @@ vac_linesize_patch_32:             subcc   %l7, 32, %l7
  * Ugly, but we cant use hardware flushing on the sun4 and we'd require
  * two instructions (Anton)
  */
-#ifdef CONFIG_SUN4
-vac_hwflush_patch1_on:         nop
-#else
 vac_hwflush_patch1_on:         addcc   %l7, -PAGE_SIZE, %l7
-#endif
 
 vac_hwflush_patch2_on:         sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 
@@ -798,42 +790,10 @@ vac_hwflush_patch2_on:            sta     %g0, [%l3 + %l7] ASI_HWFLUSHSEG
 ! %l7 = 1 for textfault
 ! We want error in %l5, vaddr in %l6
 sun4c_fault:
-#ifdef CONFIG_SUN4
-       sethi   %hi(sun4c_memerr_reg), %l4
-       ld      [%l4+%lo(sun4c_memerr_reg)], %l4  ! memerr ctrl reg addr
-       ld      [%l4], %l6              ! memerr ctrl reg
-       ld      [%l4 + 4], %l5          ! memerr vaddr reg
-       andcc   %l6, 0x80, %g0          ! check for error type
-       st      %g0, [%l4 + 4]          ! clear the error
-       be      0f                      ! normal error
-        sethi  %hi(AC_BUS_ERROR), %l4  ! bus err reg addr
-
-       call    prom_halt       ! something weird happened
-                                       ! what exactly did happen?
-                                       ! what should we do here?
-
-0:     or      %l4, %lo(AC_BUS_ERROR), %l4     ! bus err reg addr
-       lduba   [%l4] ASI_CONTROL, %l6  ! bus err reg
-
-       cmp    %l7, 1                   ! text fault?
-       be      1f                      ! yes
-        nop
-
-       ld     [%l1], %l4               ! load instruction that caused fault
-       srl     %l4, 21, %l4
-       andcc   %l4, 1, %g0             ! store instruction?
-
-       be      1f                      ! no
-        sethi  %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
-                                       ! %lo(SUN4C_SYNC_BADWRITE) = 0
-       or      %l4, %l6, %l6           ! set write bit to emulate sun4c
-1:
-#else
        sethi   %hi(AC_SYNC_ERR), %l4
        add     %l4, 0x4, %l6                   ! AC_SYNC_VA in %l6
        lda     [%l6] ASI_CONTROL, %l5          ! Address
        lda     [%l4] ASI_CONTROL, %l6          ! Error, retained for a bit
-#endif
 
        andn    %l5, 0xfff, %l5                 ! Encode all info into l7
        srl     %l6, 14, %l4
@@ -880,12 +840,7 @@ sun4c_fault:
        or      %l4, %lo(swapper_pg_dir), %l4
        sll     %l6, 2, %l6
        ld      [%l4 + %l6], %l4
-#ifdef CONFIG_SUN4
-       sethi   %hi(PAGE_MASK), %l6
-       andcc   %l4, %l6, %g0
-#else
        andcc   %l4, PAGE_MASK, %g0
-#endif
        be      sun4c_fault_fromuser
         lduXa  [%l5] ASI_SEGMAP, %l4
 
@@ -937,11 +892,7 @@ invalid_segment_patch1:
        ld      [%l6 + 0x08], %l3       ! tmp = entry->vaddr
 
        ! Flush segment from the cache.
-#ifdef CONFIG_SUN4
-       sethi   %hi((128 * 1024)), %l7
-#else
        sethi   %hi((64 * 1024)), %l7
-#endif
 9:
 vac_hwflush_patch1:
 vac_linesize_patch:
@@ -1029,12 +980,7 @@ invalid_segment_patch2:
        or      %l4, %lo(swapper_pg_dir), %l4
        sll     %l3, 2, %l3
        ld      [%l4 + %l3], %l4
-#ifndef CONFIG_SUN4
        and     %l4, PAGE_MASK, %l4
-#else
-       sethi   %hi(PAGE_MASK), %l6
-       and     %l4, %l6, %l4
-#endif
 
        srl     %l5, (PAGE_SHIFT - 2), %l6
        and     %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
index 50d9a16af795c5d675fefd40a3e17cab5f486840..2d325fd845795e32361f658736784262f56bf5c0 100644 (file)
@@ -63,15 +63,9 @@ cputypvar_sun4m:
 
        .align 4
 
-#ifndef CONFIG_SUN4
 sun4_notsup:
-       .asciz  "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n"
+       .asciz  "Sparc-Linux sun4 support does no longer exist.\n\n"
        .align 4
-#else
-sun4cdm_notsup:
-       .asciz  "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n"
-       .align 4
-#endif
 
 sun4e_notsup:
         .asciz  "Sparc-Linux sun4e support does not exist\n\n"
@@ -780,15 +774,6 @@ execute_in_high_mem:
                 nop
 
 found_version:
-#ifdef CONFIG_SUN4
-/* For people who try sun4 kernels, even if Configure.help advises them. */
-               ld      [%g7 + 0x68], %o1
-               set     sun4cdm_notsup, %o0
-               call    %o1
-                nop
-               b       halt_me
-                nop
-#endif
 /* Get the machine type via the mysterious romvec node operations. */
 
                add     %g7, 0x1c, %l1          
@@ -1150,15 +1135,6 @@ sun4c_continue_boot:
                 nop
 
 sun4_init:
-#ifdef CONFIG_SUN4
-/* There, happy now Adrian? */
-               set     cputypval, %o2          ! Let everyone know we
-               set     ' ', %o0                        ! are a "sun4 " architecture
-               stb     %o0, [%o2 + 0x4]                
-
-               b got_prop 
-                nop
-#else
                sethi   %hi(SUN4_PROM_VECTOR+0x84), %o1
                ld      [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1
                set     sun4_notsup, %o0
@@ -1170,7 +1146,7 @@ sun4_init:
                 nop
 1:             ba      1b                      ! Cannot exit into KMON
                 nop
-#endif
+
 no_sun4e_here:
                ld      [%g7 + 0x68], %o1
                set     sun4e_notsup, %o0
index fc511f3c4c18a32bd1395447ba6b32c886b37db0..223a6582e1e208c70e622c61443196c1d5de9a61 100644 (file)
 #include <asm/oplib.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>  /* Fun with Sun released architectures. */
-#ifdef CONFIG_SUN4
-#include <asm/sun4paddr.h>
-extern void sun4setup(void);
-#endif
 
 struct idprom *idprom;
 static struct idprom idprom_buffer;
@@ -101,7 +97,4 @@ void __init idprom_init(void)
                    idprom->id_ethaddr[0], idprom->id_ethaddr[1],
                    idprom->id_ethaddr[2], idprom->id_ethaddr[3],
                    idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
-#ifdef CONFIG_SUN4
-       sun4setup();
-#endif
 }
index 2a8a847764d8c84be7f8c03cc35abc261c3e613e..4f025b36934b2e53fb833c5e94f9c071fb4efbda 100644 (file)
 #include <asm/vaddrs.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
-#include <asm/sbus.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
 #include <asm/dma.h>
+#include <asm/iommu.h>
+#include <asm/io-unit.h>
+
+#include "dma.h"
 
 #define mmu_inval_dma_area(p, l)       /* Anton pulled it out for 2.4.0-xx */
 
@@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual)
        }
 }
 
-/*
- */
-void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset,
-    unsigned long size, char *name)
-{
-       return _sparc_alloc_io(phyres->flags & 0xF,
-           phyres->start + offset, size, name);
-}
-
 void __iomem *of_ioremap(struct resource *res, unsigned long offset,
                         unsigned long size, char *name)
 {
@@ -163,13 +157,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
 }
 EXPORT_SYMBOL(of_iounmap);
 
-/*
- */
-void sbus_iounmap(volatile void __iomem *addr, unsigned long size)
-{
-       iounmap(addr);
-}
-
 /*
  * Meat of mapping
  */
@@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res)
 
 #ifdef CONFIG_SBUS
 
-void sbus_set_sbus64(struct sbus_dev *sdev, int x)
+void sbus_set_sbus64(struct device *dev, int x)
 {
        printk("sbus_set_sbus64: unsupported\n");
 }
 
-extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-void __init sbus_fill_device_irq(struct sbus_dev *sdev)
-{
-       struct linux_prom_irqs irqs[PROMINTR_MAX];
-       int len;
-
-       len = prom_getproperty(sdev->prom_node, "intr",
-                              (char *)irqs, sizeof(irqs));
-       if (len != -1) {
-               sdev->num_irqs = len / 8;
-               if (sdev->num_irqs == 0) {
-                       sdev->irqs[0] = 0;
-               } else if (sparc_cpu_model == sun4d) {
-                       for (len = 0; len < sdev->num_irqs; len++)
-                               sdev->irqs[len] =
-                                       sun4d_build_irq(sdev, irqs[len].pri);
-               } else {
-                       for (len = 0; len < sdev->num_irqs; len++)
-                               sdev->irqs[len] = irqs[len].pri;
-               }
-       } else {
-               int interrupts[PROMINTR_MAX];
-
-               /* No "intr" node found-- check for "interrupts" node.
-                * This node contains SBus interrupt levels, not IPLs
-                * as in "intr", and no vector values.  We convert
-                * SBus interrupt levels to PILs (platform specific).
-                */
-               len = prom_getproperty(sdev->prom_node, "interrupts",
-                                      (char *)interrupts, sizeof(interrupts));
-               if (len == -1) {
-                       sdev->irqs[0] = 0;
-                       sdev->num_irqs = 0;
-               } else {
-                       sdev->num_irqs = len / sizeof(int);
-                       for (len = 0; len < sdev->num_irqs; len++) {
-                               sdev->irqs[len] =
-                                       sbint_to_irq(sdev, interrupts[len]);
-                       }
-               }
-       } 
-}
-
 /*
  * Allocate a chunk of memory suitable for DMA.
  * Typically devices use them for control blocks.
  * CPU may access them without any explicit flushing.
- *
- * XXX Some clever people know that sdev is not used and supply NULL. Watch.
  */
-void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
+void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp)
 {
+       struct of_device *op = to_of_device(dev);
        unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
        unsigned long va;
        struct resource *res;
@@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp)
         * XXX That's where sdev would be used. Currently we load
         * all iommu tables with the same translations.
         */
-       if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0)
+       if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
                goto err_noiommu;
 
-       /* Set the resource name, if known. */
-       if (sdev) {
-               res->name = sdev->prom_name;
-       }
+       res->name = op->node->name;
 
        return (void *)(unsigned long)res->start;
 
@@ -356,7 +296,7 @@ err_nopages:
        return NULL;
 }
 
-void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
+void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba)
 {
        struct resource *res;
        struct page *pgv;
@@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
        kfree(res);
 
        /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
-       pgv = mmu_translate_dvma(ba);
-       mmu_unmap_dma_area(ba, n);
+       pgv = virt_to_page(p);
+       mmu_unmap_dma_area(dev, ba, n);
 
        __free_pages(pgv, get_order(n));
 }
@@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba)
  * CPU view of this memory may be inconsistent with
  * a device view and explicit flushing is necessary.
  */
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction)
+dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction)
 {
        /* XXX why are some lengths signed, others unsigned? */
        if (len <= 0) {
@@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire
        if (len > 256*1024) {                   /* __get_free_pages() limit */
                return 0;
        }
-       return mmu_get_scsi_one(va, len, sdev->bus);
+       return mmu_get_scsi_one(dev, va, len);
 }
 
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction)
+void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction)
 {
-       mmu_release_scsi_one(ba, n, sdev->bus);
+       mmu_release_scsi_one(dev, ba, n);
 }
 
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-       mmu_get_scsi_sgl(sg, n, sdev->bus);
+       mmu_get_scsi_sgl(dev, sg, n);
 
        /*
         * XXX sparc64 can return a partial length here. sun4c should do this
@@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct
        return n;
 }
 
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
-{
-       mmu_release_scsi_sgl(sg, n, sdev->bus);
-}
-
-/*
- */
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
-{
-#if 0
-       unsigned long va;
-       struct resource *res;
-
-       /* We do not need the resource, just print a message if invalid. */
-       res = _sparc_find_resource(&_sparc_dvma, ba);
-       if (res == NULL)
-               panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-       va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-       /*
-        * XXX This bogosity will be fixed with the iommu rewrite coming soon
-        * to a kernel near you. - Anton
-        */
-       /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
-}
-
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction)
+void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction)
 {
-#if 0
-       unsigned long va;
-       struct resource *res;
-
-       /* We do not need the resource, just print a message if invalid. */
-       res = _sparc_find_resource(&_sparc_dvma, ba);
-       if (res == NULL)
-               panic("sbus_dma_sync_single: 0x%x\n", ba);
-
-       va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */
-       /*
-        * XXX This bogosity will be fixed with the iommu rewrite coming soon
-        * to a kernel near you. - Anton
-        */
-       /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */
-#endif
+       mmu_release_scsi_sgl(dev, sg, n);
 }
 
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-       printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n");
 }
 
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction)
+void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction)
 {
-       printk("sbus_dma_sync_sg_for_device: not implemented yet\n");
-}
-
-/* Support code for sbus_init().  */
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-       int parent_node = pn->node;
-
-       if (sparc_cpu_model == sun4d) {
-               struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
-               int num_iounit_ranges, len;
-
-               len = prom_getproperty(parent_node, "ranges",
-                                      (char *) iounit_ranges,
-                                      sizeof (iounit_ranges));
-               if (len != -1) {
-                       num_iounit_ranges =
-                               (len / sizeof(struct linux_prom_ranges));
-                       prom_adjust_ranges(sbus->sbus_ranges,
-                                          sbus->num_sbus_ranges,
-                                          iounit_ranges, num_iounit_ranges);
-               }
-       }
 }
 
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-#ifndef CONFIG_SUN4
-       struct device_node *parent = dp->parent;
-
-       if (sparc_cpu_model != sun4d &&
-           parent != NULL &&
-           !strcmp(parent->name, "iommu")) {
-               extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-
-               iommu_init(parent->node, sbus);
-       }
-
-       if (sparc_cpu_model == sun4d) {
-               extern void iounit_init(int sbi_node, int iounit_node,
-                                       struct sbus_bus *sbus);
-
-               iounit_init(dp->node, parent->node, sbus);
-       }
-#endif
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-       if (sparc_cpu_model == sun4d) {
-               struct device_node *parent = dp->parent;
-
-               sbus->devid = of_getintprop_default(parent, "device-id", 0);
-               sbus->board = of_getintprop_default(parent, "board#", 0);
-       }
-}
-
-int __init sbus_arch_preinit(void)
+static int __init sparc_register_ioport(void)
 {
        register_proc_sparc_ioport();
 
-#ifdef CONFIG_SUN4
-       {
-               extern void sun4_dvma_init(void);
-               sun4_dvma_init();
-       }
-       return 1;
-#else
        return 0;
-#endif
 }
 
-void __init sbus_arch_postinit(void)
-{
-       if (sparc_cpu_model == sun4d) {
-               extern void sun4d_init_sbi_irq(void);
-               sun4d_init_sbi_irq();
-       }
-}
+arch_initcall(sparc_register_ioport);
+
 #endif /* CONFIG_SBUS */
 
 #ifdef CONFIG_PCI
index 32ef3ebd0a88a58eca6051634db2504425753929..db75138815307780820df94178d14fd5506e1db5 100644 (file)
@@ -13,7 +13,6 @@ BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
 BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
 BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
 BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
 
 static inline void __disable_irq(unsigned int irq)
@@ -41,11 +40,6 @@ static inline void clear_clock_irq(void)
        BTFIXUP_CALL(clear_clock_irq)();
 }
 
-static inline void clear_profile_irq(int irq)
-{
-       BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
 static inline void load_profile_irq(int cpu, int limit)
 {
        BTFIXUP_CALL(load_profile_irq)(cpu, limit);
index f58c537446a87547bafbbf396a42a65b2875c924..0837bd52e28f454e2f4fc18aa003970caf3a455b 100644 (file)
@@ -29,15 +29,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
+
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -327,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent,
        return 1;
 }
 
+static int __init use_1to1_mapping(struct device_node *pp)
+{
+       /* If we have a ranges property in the parent, use it.  */
+       if (of_find_property(pp, "ranges", NULL) != NULL)
+               return 0;
+
+       /* Some SBUS devices use intermediate nodes to express
+        * hierarchy within the device itself.  These aren't
+        * real bus nodes, and don't have a 'ranges' property.
+        * But, we should still pass the translation work up
+        * to the SBUS itself.
+        */
+       if (!strcmp(pp->name, "dma") ||
+           !strcmp(pp->name, "espdma") ||
+           !strcmp(pp->name, "ledma") ||
+           !strcmp(pp->name, "lebuffer"))
+               return 0;
+
+       return 1;
+}
+
 static int of_resource_verbose;
 
 static void __init build_device_resources(struct of_device *op,
@@ -373,10 +417,7 @@ static void __init build_device_resources(struct of_device *op,
 
                flags = bus->get_flags(reg, 0);
 
-               /* If the immediate parent has no ranges property to apply,
-                * just use a 1<->1 mapping.
-                */
-               if (of_find_property(pp, "ranges", NULL) == NULL) {
+               if (use_1to1_mapping(pp)) {
                        result = of_read_addr(addr, na);
                        goto build_res;
                }
@@ -565,15 +606,6 @@ static int __init of_bus_driver_init(void)
        int err;
 
        err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-       if (!err)
-               err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-       if (!err)
-               err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
        if (!err)
                scan_of_devices();
 
index a6a6f9823370582d3b6ef0ff18206c6d072f719a..462584e55fba13bff47a39ab03ca533b8797cd05 100644 (file)
@@ -17,8 +17,6 @@
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 
-#include <asm/ebus.h>
-#include <asm/sbus.h> /* for sanity check... */
 #include <asm/swift.h> /* for cache flushing. */
 #include <asm/io.h>
 
@@ -430,7 +428,6 @@ static int __init pcic_init(void)
 
        pcic_pbm_scan_bus(pcic);
 
-       ebus_init();
        return 0;
 }
 
@@ -493,10 +490,6 @@ static void pcic_map_pci_device(struct linux_pcic *pcic,
                                 * do ioremap() before accessing PC-style I/O,
                                 * we supply virtual, ready to access address.
                                 *
-                                * Ebus devices do not come here even if
-                                * CheerIO makes a similar conversion.
-                                * See ebus.c for details.
-                                *
                                 * Note that request_region()
                                 * works for these devices.
                                 *
@@ -677,7 +670,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 }
 
 /*
- * pcic_pin_to_irq() is exported to ebus.c.
+ * pcic_pin_to_irq() is exported to bus probing code
  */
 unsigned int
 pcic_pin_to_irq(unsigned int pin, const char *name)
@@ -904,11 +897,6 @@ static void pcic_enable_irq(unsigned int irq_nr)
        local_irq_restore(flags);
 }
 
-static void pcic_clear_profile_irq(int cpu)
-{
-       printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
-}
-
 static void pcic_load_profile_irq(int cpu, unsigned int limit)
 {
        printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
@@ -934,7 +922,6 @@ void __init sun4m_pci_init_IRQ(void)
        BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
 }
 
index 7eca8871ff47cf0914c902674e5ae697c22779cf..2afcfab4f11cc011585ddc9901b64da953ed9b87 100644 (file)
@@ -8,11 +8,11 @@
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/miscdevice.h>
 #include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/auxio.h>
  * #define PMC_NO_IDLE
  */
 
-#define PMC_MINOR      MISC_DYNAMIC_MINOR
 #define PMC_OBPNAME    "SUNW,pmc"
 #define PMC_DEVNAME "pmc"
 
 #define PMC_IDLE_REG   0x00
 #define PMC_IDLE_ON            0x01
 
-volatile static u8 __iomem *regs; 
-static int pmc_regsize;
+static u8 __iomem *regs;
 
-#define pmc_readb(offs)                        (sbus_readb(regs+offs))
+#define pmc_readb(offs)                (sbus_readb(regs+offs))
 #define pmc_writeb(val, offs)  (sbus_writeb(val, regs+offs))
 
 /* 
@@ -53,31 +51,11 @@ void pmc_swift_idle(void)
 #endif
 } 
 
-static inline void pmc_free(void)
+static int __devinit pmc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       sbus_iounmap(regs, pmc_regsize);
-}
-
-static int __init pmc_probe(void)
-{
-       struct sbus_bus *sbus = NULL;
-       struct sbus_dev *sdev = NULL;
-       for_each_sbus(sbus) {
-               for_each_sbusdev(sdev, sbus) {
-                       if (!strcmp(sdev->prom_name, PMC_OBPNAME)) {
-                               goto sbus_done;
-                       }
-               }
-       }
-
-sbus_done:
-       if (!sdev) {
-               return -ENODEV;
-       }
-
-       pmc_regsize = sdev->reg_addrs[0].reg_size;
-       regs = sbus_ioremap(&sdev->resource[0], 0, 
-                                  pmc_regsize, PMC_OBPNAME);
+       regs = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]), PMC_OBPNAME);
        if (!regs) {
                printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME);
                return -ENODEV;
@@ -92,8 +70,27 @@ sbus_done:
        return 0;
 }
 
+static struct of_device_id __initdata pmc_match[] = {
+       {
+               .name = PMC_OBPNAME,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pmc_match);
+
+static struct of_platform_driver pmc_driver = {
+       .name           = "pmc",
+       .match_table    = pmc_match,
+       .probe          = pmc_probe,
+};
+
+static int __init pmc_init(void)
+{
+       return of_register_driver(&pmc_driver, &of_bus_type);
+}
+
 /* This driver is not critical to the boot process
  * and is easiest to ioremap when SBus is already
  * initialized, so we install ourselves thusly:
  */
-__initcall(pmc_probe);
+__initcall(pmc_init);
index 4bb430940a61d3c353a7501bd86b6019e5253dc5..e8c43ffe317ef120d52094122e5cdab86e8b87d9 100644 (file)
@@ -75,7 +75,7 @@ void cpu_idle(void)
 {
        /* endless idle loop with no priority at all */
        for (;;) {
-               if (ARCH_SUN4C_SUN4) {
+               if (ARCH_SUN4C) {
                        static int count = HZ;
                        static unsigned long last_jiffies;
                        static unsigned long last_faults;
index cd4fb79aa3a8e185f12d8bfcd8ec90960e2a40ff..eee5efcfe50eea300a42d43e887bf4a7b5a54c6a 100644 (file)
@@ -54,6 +54,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -77,7 +80,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
                        void *old_val = prop->value;
                        int ret;
 
+                       mutex_lock(&of_set_property_mutex);
                        ret = prom_setprop(dp->node, (char *) name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
                        err = -EINVAL;
                        if (ret >= 0) {
                                prop->value = new_val;
@@ -436,7 +442,6 @@ static void __init of_console_init(void)
 
        switch (prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                skip = 0;
                switch (*romvec->pv_stdout) {
                case PROMDEV_SCREEN:
index 9e451b21202e927a4c3bf809490e4e5237e15354..24fe3078bd4bf8d400d4b081745cd3770150e1b8 100644 (file)
@@ -213,23 +213,25 @@ void __init setup_arch(char **cmdline_p)
        /* Initialize PROM console and command line. */
        *cmdline_p = prom_getbootargs();
        strcpy(boot_command_line, *cmdline_p);
+       parse_early_param();
 
        /* Set sparc_cpu_model */
        sparc_cpu_model = sun_unknown;
-       if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; }
-       if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; }
-       if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; }
-       if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; }  /* CP-1200 with PROM 2.30 -E */
-       if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; }
-       if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; }
-       if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; }
-
-#ifdef CONFIG_SUN4
-       if (sparc_cpu_model != sun4) {
-               prom_printf("This kernel is for Sun4 architecture only.\n");
-               prom_halt();
-       }
-#endif
+       if (!strcmp(&cputypval,"sun4 "))
+               sparc_cpu_model = sun4;
+       if (!strcmp(&cputypval,"sun4c"))
+               sparc_cpu_model = sun4c;
+       if (!strcmp(&cputypval,"sun4m"))
+               sparc_cpu_model = sun4m;
+       if (!strcmp(&cputypval,"sun4s"))
+               sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */
+       if (!strcmp(&cputypval,"sun4d"))
+               sparc_cpu_model = sun4d;
+       if (!strcmp(&cputypval,"sun4e"))
+               sparc_cpu_model = sun4e;
+       if (!strcmp(&cputypval,"sun4u"))
+               sparc_cpu_model = sun4u;
+
        printk("ARCH: ");
        switch(sparc_cpu_model) {
        case sun4:
@@ -263,7 +265,7 @@ void __init setup_arch(char **cmdline_p)
        boot_flags_init(*cmdline_p);
 
        idprom_init();
-       if (ARCH_SUN4C_SUN4)
+       if (ARCH_SUN4C)
                sun4c_probe_vac();
        load_mmu();
 
index b23cea5ca5d1c197e9c9d1285eadd50d95c646fb..b0dfff84865365a595e39283e480b1ccbd9eb850 100644 (file)
 #include <asm/idprom.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/io-unit.h>
 #include <asm/bug.h>
 
@@ -127,16 +122,11 @@ EXPORT_SYMBOL(phys_cpu_present_map);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(__ndelay);
 EXPORT_SYMBOL(rtc_lock);
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
 #endif
 EXPORT_SYMBOL(io_remap_pfn_range);
-  /* P3: iounit_xxx may be needed, sun4d users */
-/* EXPORT_SYMBOL(iounit_map_dma_init); */
-/* EXPORT_SYMBOL(iounit_map_dma_page); */
 
 #ifndef CONFIG_SMP
 EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
@@ -153,24 +143,9 @@ EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one));
 EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached));
 
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
-EXPORT_SYMBOL(sbus_iounmap);
-EXPORT_SYMBOL(sbus_ioremap);
 #endif
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(insw);
index 340fc395fe2dd7491cc8bf6e351525fc506f34cc..5dc8a5769489206ba45e64b12e6d471bd7923526 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include "irq.h"
 
 #include <asm/ptrace.h>
 #include <asm/traps.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sun4paddr.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sbus.h>
-
-#if 0
-static struct resource sun4c_timer_eb = { "sun4c_timer" };
-static struct resource sun4c_intr_eb = { "sun4c_intr" };
-#endif
 
 /*
  * Bit field defines for the interrupt registers on various
@@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" };
  *
  * so don't go making it static, like I tried. sigh.
  */
-unsigned char *interrupt_enable = NULL;
-
-static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 };
-
-static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sun4c_pil_map)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4c_pil_map[sbint];
-}
+unsigned char __iomem *interrupt_enable = NULL;
 
 static void sun4c_disable_irq(unsigned int irq_nr)
 {
@@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
     
        local_irq_save(flags);
        irq_nr &= (NR_IRQS - 1);
-       current_mask = *interrupt_enable;
+       current_mask = sbus_readb(interrupt_enable);
        switch(irq_nr) {
        case 1:
                new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
@@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
                local_irq_restore(flags);
                return;
        }
-       *interrupt_enable = new_mask;
+       sbus_writeb(new_mask, interrupt_enable);
        local_irq_restore(flags);
 }
 
@@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr)
     
        local_irq_save(flags);
        irq_nr &= (NR_IRQS - 1);
-       current_mask = *interrupt_enable;
+       current_mask = sbus_readb(interrupt_enable);
        switch(irq_nr) {
        case 1:
                new_mask = ((current_mask) | SUN4C_INT_E1);
@@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr)
                local_irq_restore(flags);
                return;
        }
-       *interrupt_enable = new_mask;
+       sbus_writeb(new_mask, interrupt_enable);
        local_irq_restore(flags);
 }
 
-#define TIMER_IRQ      10    /* Also at level 14, but we ignore that one. */
-#define PROFILE_IRQ    14    /* Level14 ticker.. used by OBP for polling */
-
-volatile struct sun4c_timer_info *sun4c_timers;
+struct sun4c_timer_info {
+       u32             l10_count;
+       u32             l10_limit;
+       u32             l14_count;
+       u32             l14_limit;
+};
 
-#ifdef CONFIG_SUN4
-/* This is an ugly hack to work around the
-   current timer code, and make it work with 
-   the sun4/260 intersil 
-   */
-volatile struct sun4c_timer_info sun4_timer;
-#endif
+static struct sun4c_timer_info __iomem *sun4c_timers;
 
 static void sun4c_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-#ifdef CONFIG_SUN4
-       if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) 
-         clear_intr = sun4_timer.timer_limit10;
-       else
-#endif
-       clear_intr = sun4c_timers->timer_limit10;
-}
-
-static void sun4c_clear_profile_irq(int cpu)
-{
-       /* Errm.. not sure how to do this.. */
+       sbus_readl(&sun4c_timers->l10_limit);
 }
 
 static void sun4c_load_profile_irq(int cpu, unsigned int limit)
@@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
 
 static void __init sun4c_init_timers(irq_handler_t counter_fn)
 {
-       int irq;
+       const struct linux_prom_irqs *irq;
+       struct device_node *dp;
+       const u32 *addr;
+       int err;
+
+       dp = of_find_node_by_name(NULL, "counter-timer");
+       if (!dp) {
+               prom_printf("sun4c_init_timers: Unable to find counter-timer\n");
+               prom_halt();
+       }
 
-       /* Map the Timer chip, this is implemented in hardware inside
-        * the cache chip on the sun4c.
-        */
-#ifdef CONFIG_SUN4
-       if (idprom->id_machtype == (SM_SUN4 | SM_4_260))
-               sun4c_timers = &sun4_timer;
-       else
-#endif
-       sun4c_timers = ioremap(SUN_TIMER_PHYSADDR,
-           sizeof(struct sun4c_timer_info));
+       addr = of_get_property(dp, "address", NULL);
+       if (!addr) {
+               prom_printf("sun4c_init_timers: No address property\n");
+               prom_halt();
+       }
+
+       sun4c_timers = (void __iomem *) (unsigned long) addr[0];
+
+       irq = of_get_property(dp, "intr", NULL);
+       if (!irq) {
+               prom_printf("sun4c_init_timers: No intr property\n");
+               prom_halt();
+       }
 
        /* Have the level 10 timer tick at 100HZ.  We don't touch the
         * level 14 timer limit since we are letting the prom handle
         * them until we have a real console driver so L1-A works.
         */
-       sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4c_timers->cur_count10;
-       master_l10_limit = &sun4c_timers->timer_limit10;
+       sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit);
 
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
+       master_l10_counter = &sun4c_timers->l10_count;
+
+       err = request_irq(irq[0].pri, counter_fn,
                          (IRQF_DISABLED | SA_STATIC_ALLOC),
                          "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+       if (err) {
+               prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
                prom_halt();
        }
     
-#if 0
-       /* This does not work on 4/330 */
-       sun4c_enable_irq(10);
-#endif
-       claim_ticker14(NULL, PROFILE_IRQ, 0);
+       sun4c_disable_irq(irq[1].pri);
 }
 
 #ifdef CONFIG_SMP
@@ -215,41 +190,28 @@ static void sun4c_nop(void) {}
 
 void __init sun4c_init_IRQ(void)
 {
-       struct linux_prom_registers int_regs[2];
-       int ie_node;
+       struct device_node *dp;
+       const u32 *addr;
 
-       if (ARCH_SUN4) {
-               interrupt_enable = (char *)
-                   ioremap(sun4_ie_physaddr, PAGE_SIZE);
-       } else {
-               struct resource phyres;
-
-               ie_node = prom_searchsiblings (prom_getchild(prom_root_node),
-                                       "interrupt-enable");
-               if(ie_node == 0)
-                       panic("Cannot find /interrupt-enable node");
+       dp = of_find_node_by_name(NULL, "interrupt-enable");
+       if (!dp) {
+               prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n");
+               prom_halt();
+       }
 
-               /* Depending on the "address" property is bad news... */
-               interrupt_enable = NULL;
-               if (prom_getproperty(ie_node, "reg", (char *) int_regs,
-                                    sizeof(int_regs)) != -1) {
-                       memset(&phyres, 0, sizeof(struct resource));
-                       phyres.flags = int_regs[0].which_io;
-                       phyres.start = int_regs[0].phys_addr;
-                       interrupt_enable = (char *) sbus_ioremap(&phyres, 0,
-                           int_regs[0].reg_size, "sun4c_intr");
-               }
+       addr = of_get_property(dp, "address", NULL);
+       if (!addr) {
+               prom_printf("sun4c_init_IRQ: No address property\n");
+               prom_halt();
        }
-       if (!interrupt_enable)
-               panic("Cannot map interrupt_enable");
 
-       BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM);
+       interrupt_enable = (void __iomem *) (unsigned long) addr[0];
+
        BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
        sparc_init_timers = sun4c_init_timers;
 #ifdef CONFIG_SMP
@@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void)
        BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
        BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP);
 #endif
-       *interrupt_enable = (SUN4C_INT_ENABLE);
+       sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable);
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
index 1290b5998f831ede12dd28416cf967e088ba267c..d3cb76ce418bde420d5d7e397679091ba5cd5cf8 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -34,7 +36,6 @@
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/cacheflush.h>
 #include <asm/irq_regs.h>
 /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
 /* #define DISTRIBUTE_IRQS */
 
-struct sun4d_timer_regs *sun4d_timers;
+struct sun4d_timer_regs {
+       u32     l10_timer_limit;
+       u32     l10_cur_countx;
+       u32     l10_limit_noclear;
+       u32     ctrl;
+       u32     l10_cur_count;
+};
+
+static struct sun4d_timer_regs __iomem *sun4d_timers;
+
 #define TIMER_IRQ      10
 
 #define MAX_STATIC_ALLOC       4
 extern struct irqaction static_irqaction[MAX_STATIC_ALLOC];
 extern int static_irq_count;
-unsigned char cpu_leds[32];
-#ifdef CONFIG_SMP
 static unsigned char sbus_tid[32];
-#endif
 
 static struct irqaction *irq_action[NR_IRQS];
 extern spinlock_t irq_action_lock;
@@ -72,9 +79,9 @@ static int sbus_to_pil[] = {
 };
 
 static int nsbi;
-#ifdef CONFIG_SMP
+
+/* Exported for sun4d_smp.c */
 DEFINE_SPINLOCK(sun4d_imsk_lock);
-#endif
 
 int show_sun4d_interrupts(struct seq_file *p, void *v)
 {
@@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
        set_irq_regs(old_regs);
 }
 
-unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
-{
-       int sbusl = pil_to_sbus[irq];
-
-       if (sbusl)
-               return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot;
-       else
-               return irq;
-}
-
-static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sbus_to_pil)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4d_build_irq(sdev, sbus_to_pil[sbint]);
-}
-
 int sun4d_request_irq(unsigned int irq,
                irq_handler_t handler,
                unsigned long irqflags, const char * devname, void *dev_id)
@@ -360,36 +347,28 @@ out:
 
 static void sun4d_disable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
        int tid = sbus_tid[(irq >> 5) - 1];
        unsigned long flags;
-#endif 
        
-       if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+       if (irq < NR_IRQS)
+               return;
+
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else          
-       cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 static void sun4d_enable_irq(unsigned int irq)
 {
-#ifdef CONFIG_SMP
        int tid = sbus_tid[(irq >> 5) - 1];
        unsigned long flags;
-#endif 
        
-       if (irq < NR_IRQS) return;
-#ifdef CONFIG_SMP
+       if (irq < NR_IRQS)
+               return;
+
        spin_lock_irqsave(&sun4d_imsk_lock, flags);
        cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
        spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
-#else          
-       cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
-#endif
 }
 
 #ifdef CONFIG_SMP
@@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu)
 /* Setup IRQ distribution scheme. */
 void __init sun4d_distribute_irqs(void)
 {
+       struct device_node *dp;
+
 #ifdef DISTRIBUTE_IRQS
-       struct sbus_bus *sbus;
-       unsigned long sbus_serving_map;
+       cpumask_t sbus_serving_map;
 
        sbus_serving_map = cpu_present_map;
-       for_each_sbus(sbus) {
-               if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1))))
-                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
-               else if (cpu_present_map & (1 << (sbus->board * 2)))
-                       sbus_tid[sbus->board] = (sbus->board * 2);
-               else if (cpu_present_map & (1 << (sbus->board * 2 + 1)))
-                       sbus_tid[sbus->board] = (sbus->board * 2 + 1);
+       for_each_node_by_name(dp, "sbi") {
+               int board = of_getintprop_default(dp, "board#", 0);
+
+               if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map))
+                       sbus_tid[board] = (board * 2 + 1);
+               else if (cpu_isset(board * 2, cpu_present_map))
+                       sbus_tid[board] = (board * 2);
+               else if (cpu_isset(board * 2 + 1, cpu_present_map))
+                       sbus_tid[board] = (board * 2 + 1);
                else
-                       sbus_tid[sbus->board] = 0xff;
-               if (sbus_tid[sbus->board] != 0xff)
-                       sbus_serving_map &= ~(1 << sbus_tid[sbus->board]);
+                       sbus_tid[board] = 0xff;
+               if (sbus_tid[board] != 0xff)
+                       cpu_clear(sbus_tid[board], sbus_serving_map);
        }
-       for_each_sbus(sbus)
-               if (sbus_tid[sbus->board] == 0xff) {
+       for_each_node_by_name(dp, "sbi") {
+               int board = of_getintprop_default(dp, "board#", 0);
+               if (sbus_tid[board] == 0xff) {
                        int i = 31;
                                
-                       if (!sbus_serving_map)
+                       if (cpus_empty(sbus_serving_map))
                                sbus_serving_map = cpu_present_map;
-                       while (!(sbus_serving_map & (1 << i)))
+                       while (cpu_isset(i, sbus_serving_map))
                                i--;
-                       sbus_tid[sbus->board] = i;
-                       sbus_serving_map &= ~(1 << i);
+                       sbus_tid[board] = i;
+                       cpu_clear(i, sbus_serving_map);
                }
-       for_each_sbus(sbus) {
-               printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]);
-               set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3);
+       }
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]);
+               set_sbi_tid(devid, sbus_tid[board] << 3);
        }
 #else
-       struct sbus_bus *sbus;
        int cpuid = cpu_logical_map(1);
 
        if (cpuid == -1)
                cpuid = cpu_logical_map(0);
-       for_each_sbus(sbus) {
-               sbus_tid[sbus->board] = cpuid;
-               set_sbi_tid(sbus->devid, cpuid << 3);
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               sbus_tid[board] = cpuid;
+               set_sbi_tid(devid, cpuid << 3);
        }
        printk("All sbus IRQs directed to CPU%d\n", cpuid);
 #endif
@@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void)
  
 static void sun4d_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-       clear_intr = sun4d_timers->l10_timer_limit;
-}
-
-static void sun4d_clear_profile_irq(int cpu)
-{
-       bw_get_prof_limit(cpu);
+       sbus_readl(&sun4d_timers->l10_timer_limit);
 }
 
 static void sun4d_load_profile_irq(int cpu, unsigned int limit)
@@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
        bw_set_prof_limit(cpu, limit);
 }
 
-static void __init sun4d_init_timers(irq_handler_t counter_fn)
+static void __init sun4d_load_profile_irqs(void)
 {
-       int irq;
-       int cpu;
-       struct resource r;
-       int mid;
+       int cpu = 0, mid;
 
-       /* Map the User Timer registers. */
-       memset(&r, 0, sizeof(r));
+       while (!cpu_find_by_instance(cpu, NULL, &mid)) {
+               sun4d_load_profile_irq(mid >> 3, 0);
+               cpu++;
+       }
+}
+
+static void __init sun4d_fixup_trap_table(void)
+{
 #ifdef CONFIG_SMP
-       r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT;
-#else
-       r.start = CSR_BASE(0)+BW_TIMER_LIMIT;
+       unsigned long flags;
+       extern unsigned long lvl14_save[4];
+       struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
+       extern unsigned int real_irq_entry[], smp4d_ticker[];
+       extern unsigned int patchme_maybe_smp_msg[];
+
+       /* Adjust so that we jump directly to smp4d_ticker */
+       lvl14_save[2] += smp4d_ticker - real_irq_entry;
+
+       /* For SMP we use the level 14 ticker, however the bootup code
+        * has copied the firmware's level 14 vector into the boot cpu's
+        * trap table, we must fix this now or we get squashed.
+        */
+       local_irq_save(flags);
+       patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
+       trap_table->inst_one = lvl14_save[0];
+       trap_table->inst_two = lvl14_save[1];
+       trap_table->inst_three = lvl14_save[2];
+       trap_table->inst_four = lvl14_save[3];
+       local_flush_cache_all();
+       local_irq_restore(flags);
 #endif
-       r.flags = 0xf;
-       sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE, "user timer");
+}
 
-       sun4d_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4d_timers->l10_cur_count;
-       master_l10_limit = &sun4d_timers->l10_timer_limit;
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
+{
+       struct device_node *dp;
+       struct resource res;
+       const u32 *reg;
+       int err;
+
+       dp = of_find_node_by_name(NULL, "cpu-unit");
+       if (!dp) {
+               prom_printf("sun4d_init_timers: Unable to find cpu-unit\n");
+               prom_halt();
+       }
 
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
-                         (IRQF_DISABLED | SA_STATIC_ALLOC),
-                         "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
+       /* Which cpu-unit we use is arbitrary, we can view the bootbus timer
+        * registers via any cpu's mapping.  The first 'reg' property is the
+        * bootbus.
+        */
+       reg = of_get_property(dp, "reg", NULL);
+       if (!reg) {
+               prom_printf("sun4d_init_timers: No reg property\n");
                prom_halt();
        }
-       
-       /* Enable user timer free run for CPU 0 in BW */
-       /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */
 
-       cpu = 0;
-       while (!cpu_find_by_instance(cpu, NULL, &mid)) {
-               sun4d_load_profile_irq(mid >> 3, 0);
-               cpu++;
+       res.start = reg[1];
+       res.end = reg[2] - 1;
+       res.flags = reg[0] & 0xff;
+       sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT,
+                                 sizeof(struct sun4d_timer_regs), "user timer");
+       if (!sun4d_timers) {
+               prom_printf("sun4d_init_timers: Can't map timer regs\n");
+               prom_halt();
        }
-               
-#ifdef CONFIG_SMP
-       {
-               unsigned long flags;
-               extern unsigned long lvl14_save[4];
-               struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
-               extern unsigned int real_irq_entry[], smp4d_ticker[];
-               extern unsigned int patchme_maybe_smp_msg[];
-
-               /* Adjust so that we jump directly to smp4d_ticker */
-               lvl14_save[2] += smp4d_ticker - real_irq_entry;
-
-               /* For SMP we use the level 14 ticker, however the bootup code
-                * has copied the firmware's level 14 vector into the boot cpu's
-                * trap table, we must fix this now or we get squashed.
-                */
-               local_irq_save(flags);
-               patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
-               trap_table->inst_one = lvl14_save[0];
-               trap_table->inst_two = lvl14_save[1];
-               trap_table->inst_three = lvl14_save[2];
-               trap_table->inst_four = lvl14_save[3];
-               local_flush_cache_all();
-               local_irq_restore(flags);
+
+       sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit);
+
+       master_l10_counter = &sun4d_timers->l10_cur_count;
+
+       err = request_irq(TIMER_IRQ, counter_fn,
+                         (IRQF_DISABLED | SA_STATIC_ALLOC),
+                         "timer", NULL);
+       if (err) {
+               prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err);
+               prom_halt();
        }
-#endif
+       sun4d_load_profile_irqs();
+       sun4d_fixup_trap_table();
 }
 
 void __init sun4d_init_sbi_irq(void)
 {
-       struct sbus_bus *sbus;
-       unsigned mask;
+       struct device_node *dp;
+       int target_cpu = 0;
+
+#ifdef CONFIG_SMP
+       target_cpu = boot_cpu_id;
+#endif
 
        nsbi = 0;
-       for_each_sbus(sbus)
+       for_each_node_by_name(dp, "sbi")
                nsbi++;
        sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
        if (!sbus_actions) {
                prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
                prom_halt();
        }
-       for_each_sbus(sbus) {
-#ifdef CONFIG_SMP      
-               extern unsigned char boot_cpu_id;
-               
-               set_sbi_tid(sbus->devid, boot_cpu_id << 3);
-               sbus_tid[sbus->board] = boot_cpu_id;
-#endif
+       for_each_node_by_name(dp, "sbi") {
+               int devid = of_getintprop_default(dp, "device-id", 0);
+               int board = of_getintprop_default(dp, "board#", 0);
+               unsigned int mask;
+
+               set_sbi_tid(devid, target_cpu << 3);
+               sbus_tid[board] = target_cpu;
+
                /* Get rid of pending irqs from PROM */
-               mask = acquire_sbi(sbus->devid, 0xffffffff);
+               mask = acquire_sbi(devid, 0xffffffff);
                if (mask) {
-                       printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board);
-                       release_sbi(sbus->devid, mask);
+                       printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board);
+                       release_sbi(devid, mask);
                }
        }
 }
@@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void)
 {
        local_irq_disable();
 
-       BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
        sparc_init_timers = sun4d_init_timers;
 #ifdef CONFIG_SMP
index 446767e8f5694651b914cce1c1206796bd2f103d..ce3d45db94e9f777d3520e52c2052c33cfc93017 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
@@ -72,6 +71,17 @@ static void smp_setup_percpu_timer(void);
 extern void cpu_probe(void);
 extern void sun4d_distribute_irqs(void);
 
+static unsigned char cpu_leds[32];
+
+static inline void show_leds(int cpuid)
+{
+       cpuid &= 0x1e;
+       __asm__ __volatile__ ("stba %0, [%1] %2" : :
+                             "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]),
+                             "r" (ECSR_BASE(cpuid) | BB_LEDS),
+                             "i" (ASI_M_CTL));
+}
+
 void __init smp4d_callin(void)
 {
        int cpuid = hard_smp4d_processor_id();
index 94e02de960ea8ca614ef8b408c882082abd97940..f10317179ee607c650ab837a5bb24ef34836e1b7 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
 #include "irq.h"
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-       unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-       /* These next two registers are WRITE-ONLY and are only
-        * "on bit" sensitive, "off bits" written have NO affect.
-        */
-       unsigned int clear;  /* Clear this cpus irqs here. */
-       unsigned int set;    /* Set this cpus irqs here. */
-       unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+       u32             pending;
+       u32             clear;
+       u32             set;
 };
 
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-       struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-       unsigned int tbt;                /* IRQ's that are still pending. */
-       unsigned int irqs;               /* Master IRQ bits. */
-
-       /* Again, like the above, two these registers are WRITE-ONLY. */
-       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-       unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-       /* This register is both READ and WRITE. */
-       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+       u32             pending;
+       u32             mask;
+       u32             mask_clear;
+       u32             mask_set;
+       u32             interrupt_target;
 };
 
-static unsigned long dummy;
-
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+/* Code in entry.S needs to get at these register mappings.  */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
 
 /* Dave Redman (djhr@tadpole.co.uk)
  * The sun4m interrupt registers.
@@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy;
 
 #define        SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
 #define        SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
-#define        SUN4M_INT_M2S_WRITE     0x20000000        /* write buffer error */
-#define        SUN4M_INT_ECC           0x10000000        /* ecc memory error */
+#define        SUN4M_INT_M2S_WRITE_ERR 0x20000000        /* write buffer error */
+#define        SUN4M_INT_ECC_ERR       0x10000000        /* ecc memory error */
+#define        SUN4M_INT_VME_ERR       0x08000000        /* vme async error */
 #define        SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
 #define        SUN4M_INT_MODULE        0x00200000        /* module interrupt */
 #define        SUN4M_INT_VIDEO         0x00100000        /* onboard video */
@@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy;
 #define        SUN4M_INT_SERIAL        0x00008000        /* serial ports */
 #define        SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
 #define        SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
+#define        SUN4M_INT_VMEBITS       0x0000007F        /* vme int bits */
+
+#define        SUN4M_INT_ERROR         (SUN4M_INT_MODULE_ERR |    \
+                                SUN4M_INT_M2S_WRITE_ERR | \
+                                SUN4M_INT_ECC_ERR |       \
+                                SUN4M_INT_VME_ERR)
 
 #define SUN4M_INT_SBUS(x)      (1 << (x+7))
 #define SUN4M_INT_VME(x)       (1 << (x))
 
-/* These tables only apply for interrupts greater than 15..
- * 
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Interrupt levels used by OBP */
+#define        OBP_INT_LEVEL_SOFT      0x10
+#define        OBP_INT_LEVEL_ONBOARD   0x20
+#define        OBP_INT_LEVEL_SBUS      0x30
+#define        OBP_INT_LEVEL_VME       0x40
+
+/* Interrupt level assignment on sun4m:
+ *
+ *     level           source
+ * ------------------------------------------------------------
+ *        1            softint-1
+ *       2             softint-2, VME/SBUS level 1
+ *       3             softint-3, VME/SBUS level 2
+ *       4             softint-4, onboard SCSI
+ *       5             softint-5, VME/SBUS level 3
+ *       6             softint-6, onboard ETHERNET
+ *       7             softint-7, VME/SBUS level 4
+ *       8             softint-8, onboard VIDEO
+ *       9             softint-9, VME/SBUS level 5, Module Interrupt
+ *      10             softint-10, system counter/timer
+ *      11             softint-11, VME/SBUS level 6, Floppy
+ *      12             softint-12, Keyboard/Mouse, Serial
+ *      13             softint-13, VME/SBUS level 7, ISDN Audio
+ *      14             softint-14, per-processor counter/timer
+ *      15             softint-15, Asynchronous Errors (broadcast)
  *
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers.  The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
  *
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree.  Each 'intr' property entry is composed of
+ * two 32-bit words.  The first word is the IRQ priority value, which
+ * is what we're intersted in.  The second word is the IRQ vector, which
+ * is unused.
+ *
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled.  0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
+ *
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2.  Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp:        0x24    onboard ESP SCSI
+ * le:         0x26    onboard Lance ETHERNET
+ * p9100:      0x32    SBUS level 1 P9100 video
+ * bpp:        0x33    SBUS level 2 BPP parallel port device
+ * DBRI:       0x39    SBUS level 5 DBRI ISDN audio
+ * SUNW,leo:   0x39    SBUS level 5 LEO video
+ * pcmcia:     0x3b    SBUS level 6 PCMCIA controller
+ * uctrl:      0x3b    SBUS level 6 UCTRL device
+ * modem:      0x3d    SBUS level 7 MODEM
+ * zs:         0x2c    onboard keyboard/mouse/serial
+ * floppy:     0x2b    onboard Floppy
+ * power:      0x22    onboard power device (XXX unknown mask bit XXX)
  */
-static unsigned char irq_xlate[32] = {
-    /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
-       0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
-       0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
-};
 
-static unsigned long irq_mask[] = {
-       0,                                                /* illegal index */
-       SUN4M_INT_SCSI,                                   /*  1 irq 4 */
-       SUN4M_INT_ETHERNET,                               /*  2 irq 6 */
-       SUN4M_INT_VIDEO,                                  /*  3 irq 8 */
-       SUN4M_INT_REALTIME,                               /*  4 irq 10 */
-       SUN4M_INT_FLOPPY,                                 /*  5 irq 11 */
-       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),             /*  6 irq 12 */
-       SUN4M_INT_MODULE_ERR,                             /*  7 irq 15 */
-       SUN4M_INT_SBUS(0),                                /*  8 irq 2 */
-       SUN4M_INT_SBUS(1),                                /*  9 irq 3 */
-       SUN4M_INT_SBUS(2),                                /* 10 irq 5 */
-       SUN4M_INT_SBUS(3),                                /* 11 irq 7 */
-       SUN4M_INT_SBUS(4),                                /* 12 irq 9 */
-       SUN4M_INT_SBUS(5),                                /* 13 irq 11 */
-       SUN4M_INT_SBUS(6)                                 /* 14 irq 13 */
+static unsigned long irq_mask[0x50] = {
+       /* SMP */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* soft */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* onboard */
+       0, 0, 0, 0,
+       SUN4M_INT_SCSI,  0, SUN4M_INT_ETHERNET, 0,
+       SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+       SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+       SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+       /* sbus */
+       0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+       0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+       0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+       0, SUN4M_INT_SBUS(6), 0, 0,
+       /* vme */
+       0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+       0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+       0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+       0, SUN4M_INT_VME(6), 0, 0
 };
 
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev,
-                                      unsigned int sbint)
-{
-       if (sbint >= sizeof(sun4m_pil_map)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4m_pil_map[sbint] | 0x30;
-}
-
 static unsigned long sun4m_get_irqmask(unsigned int irq)
 {
        unsigned long mask;
     
-       if (irq > 0x20) {
-               /* OBIO/SBUS interrupts */
-               irq &= 0x1f;
-               mask = irq_mask[irq_xlate[irq]];
-               if (!mask)
-                       printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
-       } else {
-               /* Soft Interrupts will come here.
-                * Currently there is no way to trigger them but I'm sure
-                * something could be cooked up.
-                */
-               irq &= 0xf;
-               mask = SUN4M_SOFT_INT(irq);
-       }
+       if (irq < 0x50)
+               mask = irq_mask[irq];
+       else
+               mask = 0;
+
+       if (!mask)
+               printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+                      irq);
+
        return mask;
 }
 
@@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
        mask = sun4m_get_irqmask(irq_nr);
        local_irq_save(flags);
        if (irq_nr > 15)
-               sun4m_interrupts->set = mask;
+               sbus_writel(mask, &sun4m_irq_global->mask_set);
        else
-               sun4m_interrupts->cpu_intregs[cpu].set = mask;
+               sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
        local_irq_restore(flags);    
 }
 
@@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
                mask = sun4m_get_irqmask(irq_nr);
                local_irq_save(flags);
                if (irq_nr > 15)
-                       sun4m_interrupts->clear = mask;
+                       sbus_writel(mask, &sun4m_irq_global->mask_clear);
                else
-                       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+                       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
                local_irq_restore(flags);    
        } else {
                local_irq_save(flags);
-               sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+               sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
                local_irq_restore(flags);
        }
 }
@@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = {
 /*9*/  SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
 /*10*/ SUN4M_INT_REALTIME,
 /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL  | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
 /*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
 };
 
 /* We assume the caller has disabled local interrupts when these are called,
@@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = {
  */
 static void sun4m_disable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->set = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
 }
 
 static void sun4m_enable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
 }
 
 #ifdef CONFIG_SMP
 static void sun4m_send_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].set = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
 }
 
 static void sun4m_clear_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
 }
 
 static void sun4m_set_udt(int cpu)
 {
-       sun4m_interrupts->undirected_target = cpu;
+       sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
 }
 #endif
 
-#define OBIO_INTR      0x20
-#define TIMER_IRQ      (OBIO_INTR | 10)
-#define PROFILE_IRQ    (OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+       u32             l14_limit;
+       u32             l14_count;
+       u32             l14_limit_noclear;
+       u32             user_timer_start_stop;
+};
+
+static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
+
+struct sun4m_timer_global {
+       u32             l10_limit;
+       u32             l10_count;
+       u32             l10_limit_noclear;
+       u32             reserved;
+       u32             timer_config;
+};
+
+static struct sun4m_timer_global __iomem *timers_global;
+
+#define TIMER_IRQ      (OBP_INT_LEVEL_ONBOARD | 10)
 
-static struct sun4m_timer_regs *sun4m_timers;
 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
 
 static void sun4m_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-       clear_intr = sun4m_timers->l10_timer_limit;
+       sbus_readl(&timers_global->l10_limit);
 }
 
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
 {
-       volatile unsigned int clear;
-    
-       clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+       unsigned long afsr, afar, si;
+
+       printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+       /* XXX HyperSparc hack XXX */
+       __asm__ __volatile__("mov 0x500, %%g1\n\t"
+                            "lda [%%g1] 0x4, %0\n\t"
+                            "mov 0x600, %%g1\n\t"
+                            "lda [%%g1] 0x4, %1\n\t" :
+                            "=r" (afsr), "=r" (afar));
+       printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+       si = sbus_readl(&sun4m_irq_global->pending);
+       printk(KERN_ERR "si=%08lx\n", si);
+       if (si & SUN4M_INT_MODULE_ERR)
+               printk(KERN_ERR "Module async error\n");
+       if (si & SUN4M_INT_M2S_WRITE_ERR)
+               printk(KERN_ERR "MBus/SBus async error\n");
+       if (si & SUN4M_INT_ECC_ERR)
+               printk(KERN_ERR "ECC memory error\n");
+       if (si & SUN4M_INT_VME_ERR)
+               printk(KERN_ERR "VME async error\n");
+       printk(KERN_ERR "you lose buddy boy...\n");
+       show_regs(regs);
+       prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+       sbus_readl(&timers_percpu[cpu]->l14_limit);
 }
 
 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
 {
-       sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+       sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
 }
 
 static void __init sun4m_init_timers(irq_handler_t counter_fn)
 {
-       int reg_count, irq, cpu;
-       struct linux_prom_registers cnt_regs[PROMREG_MAX];
-       int obio_node, cnt_node;
-       struct resource r;
-
-       cnt_node = 0;
-       if((obio_node =
-           prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
-          (obio_node = prom_getchild (obio_node)) == 0 ||
-          (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
-               prom_printf("Cannot find /obio/counter node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "counter");
+       int i, err, len, num_cpu_timers;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+               return;
        }
-       reg_count = prom_getproperty(cnt_node, "reg",
-                                    (void *) cnt_regs, sizeof(cnt_regs));
-       reg_count = (reg_count/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to the timer registers. */
-       prom_apply_obio_ranges(cnt_regs, reg_count);
-    
-       cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
-       cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
-       cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
-       for(obio_node = 1; obio_node < 4; obio_node++) {
-               cnt_regs[obio_node].phys_addr =
-                       cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
-               cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
-               cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+               return;
        }
 
-       memset((char*)&r, 0, sizeof(struct resource));
-       /* Map the per-cpu Counter registers. */
-       r.flags = cnt_regs[0].which_io;
-       r.start = cnt_regs[0].phys_addr;
-       sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
-       /* Map the system Counter register. */
-       /* XXX Here we expect consequent calls to yeld adjusent maps. */
-       r.flags = cnt_regs[4].which_io;
-       r.start = cnt_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
-       sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4m_timers->l10_cur_count;
-       master_l10_limit = &sun4m_timers->l10_timer_limit;
-
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
-                         (IRQF_DISABLED | SA_STATIC_ALLOC),
-                         "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
-               prom_halt();
+       num_cpu_timers = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_timers; i++) {
+               timers_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
        }
-   
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               for(cpu = 0; cpu < 4; cpu++)
-                       sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
-               sun4m_interrupts->set = SUN4M_INT_E14;
-       } else {
-               sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+       timers_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_timers];
+
+       sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+       master_l10_counter = &timers_global->l10_count;
+
+       err = request_irq(TIMER_IRQ, counter_fn,
+                         (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+       if (err) {
+               printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+                       err);
+               return;
        }
+
+       for (i = 0; i < num_cpu_timers; i++)
+               sbus_writel(0, &timers_percpu[i]->l14_limit);
+       if (num_cpu_timers == 4)
+               sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
 #ifdef CONFIG_SMP
        {
                unsigned long flags;
@@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
 
 void __init sun4m_init_IRQ(void)
 {
-       int ie_node,i;
-       struct linux_prom_registers int_regs[PROMREG_MAX];
-       int num_regs;
-       struct resource r;
-       int mid;
-    
-       local_irq_disable();
-       if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
-          (ie_node = prom_getchild (ie_node)) == 0 ||
-          (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
-               prom_printf("Cannot find /obio/interrupt node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+       int len, i, mid, num_cpu_iregs;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+               return;
        }
-       num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
-                                   sizeof(int_regs));
-       num_regs = (num_regs/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to these registers. */
-       prom_apply_obio_ranges(int_regs, num_regs);
-    
-       int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
-       int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
-       int_regs[4].which_io = int_regs[num_regs-1].which_io;
-       for(ie_node = 1; ie_node < 4; ie_node++) {
-               int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
-               int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
-               int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+               return;
        }
 
-       memset((char *)&r, 0, sizeof(struct resource));
-       /* Map the interrupt registers for all possible cpus. */
-       r.flags = int_regs[0].which_io;
-       r.start = int_regs[0].phys_addr;
-       sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
+       num_cpu_iregs = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_iregs; i++) {
+               sun4m_irq_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
+       }
+       sun4m_irq_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_iregs];
 
-       /* Map the system interrupt control registers. */
-       r.flags = int_regs[4].which_io;
-       r.start = int_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
+       local_irq_disable();
 
-       sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+       sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
        for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
-               sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
-
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               /* system wide interrupts go to cpu 0, this should always
-                * be safe because it is guaranteed to be fitted or OBP doesn't
-                * come up
-                *
-                * Not sure, but writing here on SLAVIO systems may puke
-                * so I don't do it unless there is more than 1 cpu.
-                */
-               irq_rcvreg = (unsigned long *)
-                               &sun4m_interrupts->undirected_target;
-               sun4m_interrupts->undirected_target = 0;
-       }
-       BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
+               sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
+
+       if (num_cpu_iregs == 4)
+               sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
        BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
        sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
@@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void)
        BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
 #endif
+
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }
index 9964890dc1dbe521b0db97ecef41ea076da8f0ca..0c564ba9e70938727e8460ae2a78806e268893bd 100644 (file)
@@ -315,6 +315,8 @@ void smp4m_cross_call_irq(void)
        ccall_info.processors_out[i] = 1;
 }
 
+extern void sun4m_clear_profile_irq(int cpu);
+
 void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
@@ -322,7 +324,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
 
        old_regs = set_irq_regs(regs);
 
-       clear_profile_irq(cpu);
+       sun4m_clear_profile_irq(cpu);
 
        profile_tick(CPU_PROFILING);
 
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c
deleted file mode 100644 (file)
index 229a52f..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* sun4setup.c: Setup the hardware address of various items in the sun4
- *             architecture. Called from idprom_init
- *
- * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca)
- */
-
-#include <asm/page.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h>
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-int sun4_memreg_physaddr;
-int sun4_ie_physaddr;
-int sun4_clock_physaddr;
-int sun4_timer_physaddr;
-int sun4_eth_physaddr;
-int sun4_si_physaddr;
-int sun4_bwtwo_physaddr;
-int sun4_zs0_physaddr;
-int sun4_zs1_physaddr;
-int sun4_dma_physaddr;
-int sun4_esp_physaddr;
-int sun4_ie_physaddr; 
-
-void __init sun4setup(void)
-{
-       printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). ");
-       /*
-         setup standard sun4 info
-         */
-       sun4_ie_physaddr=SUN4_IE_PHYSADDR;
-
-       /*
-         setup model specific info
-         */
-       switch(idprom->id_machtype) {
-               case (SM_SUN4 | SM_4_260 ):
-                       printk("Setup for a SUN4/260\n");
-                       sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_200_SI_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR;
-                       break;
-               case (SM_SUN4 | SM_4_330 ):
-                       printk("Setup for a SUN4/330\n");
-                       sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR;
-                       break;
-               case (SM_SUN4 | SM_4_470 ):
-                       printk("Setup for a SUN4/470\n");
-                       sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR;
-                       sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR;
-                       sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR;
-                       sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR;
-                       sun4_si_physaddr=SUN4_UNUSED_PHYSADDR;
-                       sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR;
-                       sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR;
-                       sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR;
-                       break;
-               default:
-                       ;
-       }
-}
-
index 4d73421559c3aa1c62c79b77210fdabc9f5497fb..03035c852a43f8e751f5bb8ba16e3f767c9bc9fb 100644 (file)
@@ -53,7 +53,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
        /* See asm-sparc/uaccess.h */
        if (len > TASK_SIZE - PAGE_SIZE)
                return -ENOMEM;
-       if (ARCH_SUN4C_SUN4 && len > 0x20000000)
+       if (ARCH_SUN4C && len > 0x20000000)
                return -ENOMEM;
        if (!addr)
                addr = TASK_UNMAPPED_BASE;
@@ -65,7 +65,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
 
        for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
                /* At this point:  (!vmm || addr < vmm->vm_end). */
-               if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) {
+               if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) {
                        addr = PAGE_OFFSET;
                        vmm = find_vma(current->mm, PAGE_OFFSET);
                }
@@ -81,7 +81,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
 
 asmlinkage unsigned long sparc_brk(unsigned long brk)
 {
-       if(ARCH_SUN4C_SUN4) {
+       if(ARCH_SUN4C) {
                if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000))
                        return current->mm->brk;
        }
@@ -221,7 +221,7 @@ out:
 
 int sparc_mmap_check(unsigned long addr, unsigned long len)
 {
-       if (ARCH_SUN4C_SUN4 &&
+       if (ARCH_SUN4C &&
            (len > 0x20000000 ||
             (addr < 0xe0000000 && addr + len > 0x20000000)))
                return -EINVAL;
index 707bfda86570d2acb9d139404b08dd15849b679e..138bbf5f8724a935d9916f3cf126560ee97a3c38 100644 (file)
@@ -1,31 +1,12 @@
 /* tick14.c
- * linux/arch/sparc/kernel/tick14.c
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
  *
  * This file handles the Sparc specific level14 ticker
  * This is really useful for profiling OBP uses it for keyboard
  * aborts and other stuff.
- *
- *
  */
-#include <linux/errno.h>
-#include <linux/sched.h>
 #include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/timex.h>
-#include <linux/interrupt.h>
-
-#include <asm/oplib.h>
-#include <asm/timer.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#include "irq.h"
 
 extern unsigned long lvl14_save[5];
 static unsigned long *linux_lvl14 = NULL;
@@ -56,31 +37,3 @@ void install_obp_ticker(void)
        linux_lvl14[2] =  obp_lvl14[2];
        linux_lvl14[3] =  obp_lvl14[3]; 
 }
-
-void claim_ticker14(irq_handler_t handler,
-                   int irq_nr, unsigned int timeout )
-{
-       int cpu = smp_processor_id();
-
-       /* first we copy the obp handler instructions
-        */
-       __disable_irq(irq_nr);
-       if (!handler)
-               return;
-    
-       linux_lvl14 = (unsigned long *)lvl14_save[4];
-       obp_lvl14[0] = linux_lvl14[0];
-       obp_lvl14[1] = linux_lvl14[1];
-       obp_lvl14[2] = linux_lvl14[2];
-       obp_lvl14[3] = linux_lvl14[3];
-
-       if (!request_irq(irq_nr,
-                        handler,
-                        (IRQF_DISABLED | SA_STATIC_ALLOC),
-                        "counter14",
-                        NULL)) {
-               install_linux_ticker();
-               load_profile_irq(cpu, timeout);
-               __enable_irq(irq_nr);
-       }
-}
index 0762f5db19240d171a0c0f3beb8fc44ad5ab5402..62c1d94cb4348e832c7b0d993823cc69707df5e2 100644 (file)
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/timex.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/profile.h>
+#include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
 #include <asm/timer.h>
-#include <asm/mostek.h>
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/idprom.h>
 #include <asm/machines.h>
-#include <asm/sun4paddr.h>
 #include <asm/page.h>
 #include <asm/pcic.h>
 #include <asm/irq_regs.h>
 #include "irq.h"
 
 DEFINE_SPINLOCK(rtc_lock);
-static enum sparc_clock_type sp_clock_typ;
-DEFINE_SPINLOCK(mostek_lock);
-void __iomem *mstk48t02_regs = NULL;
-static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
 static int set_rtc_mmss(unsigned long);
 static int sbus_do_settimeofday(struct timespec *tv);
 
-#ifdef CONFIG_SUN4
-struct intersil *intersil_clock;
-#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
-       (intsil_cmd)
-
-#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
-       (intsil_cmd)
-
-#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
-       ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-         INTERSIL_INTR_ENABLE))
-
-#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
-       ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
-         INTERSIL_INTR_ENABLE))
-
-#define intersil_read_intr(intersil_reg, towhere) towhere = \
-       intersil_reg->int_intr_reg
-
-#endif
-
 unsigned long profile_pc(struct pt_regs *regs)
 {
        extern char __copy_user_begin[], __copy_user_end[];
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs)
 EXPORT_SYMBOL(profile_pc);
 
 __volatile__ unsigned int *master_l10_counter;
-__volatile__ unsigned int *master_l10_limit;
 
 /*
  * timer_interrupt() needs to keep up the real-time clock,
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
 
        /* Protect counter clear so that do_gettimeoffset works */
        write_seqlock(&xtime_lock);
-#ifdef CONFIG_SUN4
-       if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
-          (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
-               int temp;
-               intersil_read_intr(intersil_clock, temp);
-               /* re-enable the irq */
-               enable_pil_irq(10);
-       }
-#endif
+
        clear_clock_irq();
 
        do_timer(1);
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __devinit kick_start_clock(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned char sec;
-       int i, count;
-
-       prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn on the kick start bit to start the oscillator. */
-       regs->creg |= MSTK_CREG_WRITE;
-       regs->sec &= ~MSTK_STOP;
-       regs->hour |= MSTK_KICK_START;
-       regs->creg &= ~MSTK_CREG_WRITE;
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Delay to allow the clock oscillator to start. */
-       sec = MSTK_REG_SEC(regs);
-       for (i = 0; i < 3; i++) {
-               while (sec == MSTK_REG_SEC(regs))
-                       for (count = 0; count < 100000; count++)
-                               /* nothing */ ;
-               prom_printf(".");
-               sec = regs->sec;
-       }
-       prom_printf("\n");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn off kick start and set a "valid" time and date. */
-       regs->creg |= MSTK_CREG_WRITE;
-       regs->hour &= ~MSTK_KICK_START;
-       MSTK_SET_REG_SEC(regs,0);
-       MSTK_SET_REG_MIN(regs,0);
-       MSTK_SET_REG_HOUR(regs,0);
-       MSTK_SET_REG_DOW(regs,5);
-       MSTK_SET_REG_DOM(regs,1);
-       MSTK_SET_REG_MONTH(regs,8);
-       MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-       regs->creg &= ~MSTK_CREG_WRITE;
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Ensure the kick start bit is off. If it isn't, turn it off. */
-       while (regs->hour & MSTK_KICK_START) {
-               prom_printf("CLOCK: Kick start still on!\n");
-
-               spin_lock_irq(&mostek_lock);
-               regs->creg |= MSTK_CREG_WRITE;
-               regs->hour &= ~MSTK_KICK_START;
-               regs->creg &= ~MSTK_CREG_WRITE;
-               spin_unlock_irq(&mostek_lock);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs = pdata->ioaddr;
+       unsigned char val = readb(regs + ofs);
+
+       /* the year 0 is 1968 */
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               val += 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
        }
-
-       prom_printf("CLOCK: Kick start procedure successful.\n");
-}
-
-/* Return nonzero if the clock chip battery is low. */
-static inline int has_low_battery(void)
-{
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned char data1, data2;
-
-       spin_lock_irq(&mostek_lock);
-       data1 = regs->eeprom[0];        /* Read some data. */
-       regs->eeprom[0] = ~data1;       /* Write back the complement. */
-       data2 = regs->eeprom[0];        /* Read back the complement. */
-       regs->eeprom[0] = data1;        /* Restore the original value. */
-       spin_unlock_irq(&mostek_lock);
-
-       return (data1 == data2);        /* Was the write blocked? */
+       return val;
 }
 
-static void __devinit mostek_set_system_time(void)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
 {
-       unsigned int year, mon, day, hour, min, sec;
-       struct mostek48t02 *mregs;
-
-       mregs = (struct mostek48t02 *)mstk48t02_regs;
-       if(!mregs) {
-               prom_printf("Something wrong, clock regs not mapped yet.\n");
-               prom_halt();
-       }               
-       spin_lock_irq(&mostek_lock);
-       mregs->creg |= MSTK_CREG_READ;
-       sec = MSTK_REG_SEC(mregs);
-       min = MSTK_REG_MIN(mregs);
-       hour = MSTK_REG_HOUR(mregs);
-       day = MSTK_REG_DOM(mregs);
-       mon = MSTK_REG_MONTH(mregs);
-       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-        set_normalized_timespec(&wall_to_monotonic,
-                                -xtime.tv_sec, -xtime.tv_nsec);
-       mregs->creg &= ~MSTK_CREG_READ;
-       spin_unlock_irq(&mostek_lock);
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs = pdata->ioaddr;
+
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               if (val < 0x68)
+                       val += 0x32;
+               else
+                       val -= 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+               if ((val & 0xf0) > 0x9A)
+                       val += 0x60;
+       }
+       writeb(val, regs + ofs);
 }
 
-/* Probe for the real time clock chip on Sun4 */
-static inline void sun4_clock_probe(void)
-{
-#ifdef CONFIG_SUN4
-       int temp;
-       struct resource r;
-
-       memset(&r, 0, sizeof(r));
-       if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
-               sp_clock_typ = MSTK48T02;
-               r.start = sun4_clock_physaddr;
-               mstk48t02_regs = sbus_ioremap(&r, 0,
-                                      sizeof(struct mostek48t02), NULL);
-               mstk48t08_regs = NULL;  /* To catch weirdness */
-               intersil_clock = NULL;  /* just in case */
-
-               /* Kick start the clock if it is completely stopped. */
-               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-                       kick_start_clock();
-       } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
-               /* intersil setup code */
-               printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
-               sp_clock_typ = INTERSIL;
-               r.start = sun4_clock_physaddr;
-               intersil_clock = (struct intersil *) 
-                   sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
-               mstk48t02_regs = 0;  /* just be sure */
-               mstk48t08_regs = NULL;  /* ditto */
-               /* initialise the clock */
-
-               intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-
-               intersil_start(intersil_clock);
-
-               intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-                intersil_read_intr(intersil_clock, temp);
-                while (!(temp & 0x80))
-                        intersil_read_intr(intersil_clock, temp);
-
-               intersil_stop(intersil_clock);
+static struct m48t59_plat_data m48t59_data = {
+       .read_byte = mostek_read_byte,
+       .write_byte = mostek_write_byte,
+};
 
-       }
-#endif
-}
+/* resource is set at runtime */
+static struct platform_device m48t59_rtc = {
+       .name           = "rtc-m48t59",
+       .id             = 0,
+       .num_resources  = 1,
+       .dev    = {
+               .platform_data = &m48t59_data,
+       },
+};
 
-#ifndef CONFIG_SUN4
 static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
        if (!model)
                return -ENODEV;
 
+       m48t59_rtc.resource = &op->resource[0];
        if (!strcmp(model, "mk48t02")) {
-               sp_clock_typ = MSTK48T02;
-
                /* Map the clock register io area read-only */
-               mstk48t02_regs = of_ioremap(&op->resource[0], 0,
-                                           sizeof(struct mostek48t02),
-                                           "mk48t02");
-               mstk48t08_regs = NULL;  /* To catch weirdness */
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               2048, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T02;
        } else if (!strcmp(model, "mk48t08")) {
-               sp_clock_typ = MSTK48T08;
-               mstk48t08_regs = of_ioremap(&op->resource[0], 0,
-                                           sizeof(struct mostek48t08),
-                                           "mk48t08");
-
-               mstk48t02_regs = &mstk48t08_regs->regs;
+               m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
+                                               8192, "rtc-m48t59");
+               m48t59_data.type = M48T59RTC_TYPE_M48T08;
        } else
                return -ENODEV;
 
-       /* Report a low battery voltage condition. */
-       if (has_low_battery())
-               printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
-
-       /* Kick start the clock if it is completely stopped. */
-       if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-               kick_start_clock();
-
-       mostek_set_system_time();
+       if (platform_device_register(&m48t59_rtc) < 0)
+               printk(KERN_ERR "Registering RTC device failed\n");
 
        return 0;
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata clock_match[] = {
        {
                .name = "eeprom",
        },
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = {
        .match_table    = clock_match,
        .probe          = clock_probe,
        .driver         = {
-               .name   = "clock",
+               .name   = "rtc",
        },
 };
 
@@ -364,7 +219,6 @@ static int __init clock_init(void)
  * need to see the clock registers.
  */
 fs_initcall(clock_init);
-#endif /* !CONFIG_SUN4 */
 
 static void __init sbus_time_init(void)
 {
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void)
        BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
        btfixup();
 
-       if (ARCH_SUN4)
-               sun4_clock_probe();
-
        sparc_init_timers(timer_interrupt);
        
-#ifdef CONFIG_SUN4
-       if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
-               mostek_set_system_time();
-       } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
-               /* initialise the intersil on sun4 */
-               unsigned int year, mon, day, hour, min, sec;
-               int temp;
-               struct intersil *iregs;
-
-               iregs=intersil_clock;
-               if(!iregs) {
-                       prom_printf("Something wrong, clock regs not mapped yet.\n");
-                       prom_halt();
-               }
-
-               intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
-               disable_pil_irq(10);
-               intersil_stop(iregs);
-               intersil_read_intr(intersil_clock, temp);
-
-               temp = iregs->clk.int_csec;
-
-               sec = iregs->clk.int_sec;
-               min = iregs->clk.int_min;
-               hour = iregs->clk.int_hour;
-               day = iregs->clk.int_day;
-               mon = iregs->clk.int_month;
-               year = MSTK_CVT_YEAR(iregs->clk.int_year);
-
-               enable_pil_irq(10);
-               intersil_start(iregs);
-
-               xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                      -xtime.tv_sec, -xtime.tv_nsec);
-               printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
-       }
-#endif
-
        /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
        local_irq_enable();
 }
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv)
        return 0;
 }
 
-/*
- * BUG: This routine does not handle hour overflow properly; it just
- *      sets the minutes. Usually you won't notice until after reboot!
- */
-static int set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long secs)
 {
-       int real_seconds, real_minutes, mostek_minutes;
-       struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
-       unsigned long flags;
-#ifdef CONFIG_SUN4
-       struct intersil *iregs = intersil_clock;
-       int temp;
-#endif
+       struct rtc_device *rtc = rtc_class_open("rtc0");
+       int err = -1;
 
-       /* Not having a register set can lead to trouble. */
-       if (!regs) {
-#ifdef CONFIG_SUN4
-               if(!iregs)
-               return -1;
-               else {
-                       temp = iregs->clk.int_csec;
-
-                       mostek_minutes = iregs->clk.int_min;
-
-                       real_seconds = nowtime % 60;
-                       real_minutes = nowtime / 60;
-                       if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-                               real_minutes += 30;     /* correct for half hour time zone */
-                       real_minutes %= 60;
-
-                       if (abs(real_minutes - mostek_minutes) < 30) {
-                               intersil_stop(iregs);
-                               iregs->clk.int_sec=real_seconds;
-                               iregs->clk.int_min=real_minutes;
-                               intersil_start(iregs);
-                       } else {
-                               printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                                      mostek_minutes, real_minutes);
-                               return -1;
-                       }
-                       
-                       return 0;
-               }
-#endif
+       if (rtc) {
+               err = rtc_set_mmss(rtc, secs);
+               rtc_class_close(rtc);
        }
 
-       spin_lock_irqsave(&mostek_lock, flags);
-       /* Read the current RTC minutes. */
-       regs->creg |= MSTK_CREG_READ;
-       mostek_minutes = MSTK_REG_MIN(regs);
-       regs->creg &= ~MSTK_CREG_READ;
-
-       /*
-        * since we're only adjusting minutes and seconds,
-        * don't interfere with hour overflow. This avoids
-        * messing with unknown time zones but requires your
-        * RTC not to be off by more than 15 minutes
-        */
-       real_seconds = nowtime % 60;
-       real_minutes = nowtime / 60;
-       if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
-               real_minutes += 30;     /* correct for half hour time zone */
-       real_minutes %= 60;
-
-       if (abs(real_minutes - mostek_minutes) < 30) {
-               regs->creg |= MSTK_CREG_WRITE;
-               MSTK_SET_REG_SEC(regs,real_seconds);
-               MSTK_SET_REG_MIN(regs,real_minutes);
-               regs->creg &= ~MSTK_CREG_WRITE;
-               spin_unlock_irqrestore(&mostek_lock, flags);
-               return 0;
-       } else {
-               spin_unlock_irqrestore(&mostek_lock, flags);
-               return -1;
-       }
+       return err;
 }
index 5d45d5fd8c99a150d75a6e2f0f1b489181b9c3a2..2b7d50659036e2daa54e47e7deb23c875f7a6726 100644 (file)
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs)
 {
 }
 
-void sun4m_nmi(struct pt_regs *regs)
-{
-       unsigned long afsr, afar;
-
-       printk("Aieee: sun4m NMI received!\n");
-       /* XXX HyperSparc hack XXX */
-       __asm__ __volatile__("mov 0x500, %%g1\n\t"
-                            "lda [%%g1] 0x4, %0\n\t"
-                            "mov 0x600, %%g1\n\t"
-                            "lda [%%g1] 0x4, %1\n\t" :
-                            "=r" (afsr), "=r" (afar));
-       printk("afsr=%08lx afar=%08lx\n", afsr, afar);
-       printk("you lose buddy boy...\n");
-       show_regs(regs);
-       prom_halt();
-}
-
 void sun4d_nmi(struct pt_regs *regs)
 {
        printk("Aieee: sun4d NMI received!\n");
index 109c8b22cb38b89ae41b2d49889a952a7775a99b..ea88955d97ffe6f10ee6dd085e57ae593f0f54b1 100644 (file)
@@ -3,13 +3,8 @@
 
 EXTRA_AFLAGS := -ansi
 
-obj-y    := fault.o init.o loadmmu.o generic.o extable.o btfixup.o
-
-ifeq ($(CONFIG_SUN4),y)
-obj-y   += nosrmmu.o
-else
-obj-y   += srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
-endif
+obj-y  := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
+           srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
 
 ifdef CONFIG_HIGHMEM
 obj-y  += highmem.o
index a312d127d47a56b63cf93b713a3eeea695d3f58d..5175ac2f4820c603d55e5fba0c06b735080edf96 100644 (file)
 
 extern char *srmmu_name;
 static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for ";
-#ifdef CONFIG_SUN4
-static char str_sun4c[] __initdata = "sun4\n";
-#else
 static char str_sun4c[] __initdata = "sun4c\n";
-#endif
 static char str_srmmu[] __initdata = "srmmu[%s]/";
 static char str_iommu[] __initdata = "iommu\n";
 static char str_iounit[] __initdata = "io-unit\n";
@@ -86,7 +82,7 @@ void __init btfixup(void)
        if (!visited) {
                visited++;
                printk(version);
-               if (ARCH_SUN4C_SUN4)
+               if (ARCH_SUN4C)
                        printk(str_sun4c);
                else {
                        printk(str_srmmu, srmmu_name);
index 3604c2e86709800455e949d27beabac11fdea949..a507e1174662e2bd0072a739d217a7480bcd60c2 100644 (file)
@@ -191,7 +191,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
         * only copy the information from the master page table,
         * nothing more.
         */
-       if (!ARCH_SUN4C_SUN4 && address >= TASK_SIZE)
+       if (!ARCH_SUN4C && address >= TASK_SIZE)
                goto vmalloc_fault;
 
        info.si_code = SEGV_MAPERR;
index e103f1bb3777ebdb11e72aea72fa399e11c02ac1..677c1e187a23e57b2fd2cf370b4aa1ae8a52ad4a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/bootmem.h>
 #include <linux/pagemap.h>
+#include <linux/poison.h>
 
 #include <asm/system.h>
 #include <asm/vac-ops.h>
@@ -480,6 +481,7 @@ void free_initmem (void)
        for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
                struct page *p;
 
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
                p = virt_to_page(addr);
 
                ClearPageReserved(p);
@@ -488,20 +490,26 @@ void free_initmem (void)
                totalram_pages++;
                num_physpages++;
        }
-       printk (KERN_INFO "Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+       printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+               (&__init_end - &__init_begin) >> 10);
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
        if (start < end)
-               printk (KERN_INFO "Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+               printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+                       (end - start) >> 10);
        for (; start < end; start += PAGE_SIZE) {
-               struct page *p = virt_to_page(start);
+               struct page *p;
+
+               memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+               p = virt_to_page(start);
 
                ClearPageReserved(p);
                init_page_count(p);
                __free_page(p);
+               totalram_pages++;
                num_physpages++;
        }
 }
index f167835db3dffe7a492d01f3473e442c3a092be2..daadf5f88050bb8a11ab728d8a2460233e2914ce 100644 (file)
 #include <linux/highmem.h>     /* pte_offset_map => kmap_atomic */
 #include <linux/bitops.h>
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/io-unit.h>
 #include <asm/mxcc.h>
 #define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
 #define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
 
-void __init
-iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
+static void __init iounit_iommu_init(struct of_device *op)
 {
-       iopte_t *xpt, *xptend;
        struct iounit_struct *iounit;
-       struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-       struct resource r;
+       iopte_t *xpt, *xptend;
 
        iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
        if (!iounit) {
@@ -55,18 +53,13 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
        iounit->rotor[1] = IOUNIT_BMAP2_START;
        iounit->rotor[2] = IOUNIT_BMAPM_START;
 
-       xpt = NULL;
-       if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
-                           sizeof(iommu_promregs)) != -1) {
-               prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
-               memset(&r, 0, sizeof(r));
-               r.flags = iommu_promregs[2].which_io;
-               r.start = iommu_promregs[2].phys_addr;
-               xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
+       xpt = of_ioremap(&op->resource[2], 0, PAGE_SIZE * 16, "XPT");
+       if (!xpt) {
+               prom_printf("SUN4D: Cannot map External Page Table.");
+               prom_halt();
        }
-       if(!xpt) panic("Cannot map External Page Table.");
        
-       sbus->ofdev.dev.archdata.iommu = iounit;
+       op->dev.archdata.iommu = iounit;
        iounit->page_table = xpt;
        spin_lock_init(&iounit->lock);
        
@@ -75,6 +68,25 @@ iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
                iopte_val(*xpt++) = 0;
 }
 
+static int __init iounit_init(void)
+{
+       extern void sun4d_init_sbi_irq(void);
+       struct device_node *dp;
+
+       for_each_node_by_name(dp, "sbi") {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               iounit_iommu_init(op);
+               of_propagate_archdata(op);
+       }
+
+       sun4d_init_sbi_irq();
+
+       return 0;
+}
+
+subsys_initcall(iounit_init);
+
 /* One has to hold iounit->lock to call this */
 static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
 {
@@ -124,10 +136,10 @@ nexti:    scan = find_next_zero_bit(iounit->bmap, limit, scan);
        return vaddr;
 }
 
-static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iounit_get_scsi_one(struct device *dev, char *vaddr, unsigned long len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long ret, flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
        
        spin_lock_irqsave(&iounit->lock, flags);
        ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
@@ -135,10 +147,10 @@ static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus
        return ret;
 }
 
-static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
        /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
        spin_lock_irqsave(&iounit->lock, flags);
@@ -151,10 +163,10 @@ static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus
        spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iounit_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
        
        spin_lock_irqsave(&iounit->lock, flags);
        len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
@@ -165,11 +177,11 @@ static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_
        spin_unlock_irqrestore(&iounit->lock, flags);
 }
 
-static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long flags;
        unsigned long vaddr, len;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 
        spin_lock_irqsave(&iounit->lock, flags);
        while (sz != 0) {
@@ -185,12 +197,12 @@ static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_
 }
 
 #ifdef CONFIG_SBUS
-static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
+static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len)
 {
+       struct iounit_struct *iounit = dev->archdata.iommu;
        unsigned long page, end;
        pgprot_t dvma_prot;
        iopte_t *iopte;
-       struct sbus_bus *sbus;
 
        *pba = addr;
 
@@ -212,12 +224,8 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
                        
                        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
 
-                       for_each_sbus(sbus) {
-                               struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-                               iopte = (iopte_t *)(iounit->page_table + i);
-                               *iopte = MKIOPTE(__pa(page));
-                       }
+                       iopte = (iopte_t *)(iounit->page_table + i);
+                       *iopte = MKIOPTE(__pa(page));
                }
                addr += PAGE_SIZE;
                va += PAGE_SIZE;
@@ -228,23 +236,10 @@ static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, in
        return 0;
 }
 
-static void iounit_unmap_dma_area(unsigned long addr, int len)
+static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int len)
 {
        /* XXX Somebody please fill this in */
 }
-
-/* XXX We do not pass sbus device here, bad. */
-static struct page *iounit_translate_dvma(unsigned long addr)
-{
-       struct sbus_bus *sbus = sbus_root;      /* They are all the same */
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-       int i;
-       iopte_t *iopte;
-
-       i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
-       iopte = (iopte_t *)(iounit->page_table + i);
-       return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
-}
 #endif
 
 static char *iounit_lockarea(char *vaddr, unsigned long len)
@@ -271,54 +266,5 @@ void __init ld_mmu_iounit(void)
 #ifdef CONFIG_SBUS
        BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 }
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-       int i, j, k, npages;
-       unsigned long rotor, scan, limit;
-       unsigned long flags;
-       __u32 ret;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-
-        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
-       i = 0x0213;
-       spin_lock_irqsave(&iounit->lock, flags);
-next:  j = (i & 15);
-       rotor = iounit->rotor[j - 1];
-       limit = iounit->limit[j];
-       scan = rotor;
-nexti: scan = find_next_zero_bit(iounit->bmap, limit, scan);
-       if (scan + npages > limit) {
-               if (limit != rotor) {
-                       limit = rotor;
-                       scan = iounit->limit[j - 1];
-                       goto nexti;
-               }
-               i >>= 4;
-               if (!(i & 15))
-                       panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
-               goto next;
-       }
-       for (k = 1, scan++; k < npages; k++)
-               if (test_bit(scan++, iounit->bmap))
-                       goto nexti;
-       iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
-       scan -= npages;
-       ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
-       for (k = 0; k < npages; k++, scan++)
-               set_bit(scan, iounit->bmap);
-       spin_unlock_irqrestore(&iounit->lock, flags);
-       return ret;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-       int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
-       struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
-       
-       iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
-       return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
-}
index 4b934270f05e062c0a3c1519b3e9a1c1a51b3632..e7a499e3aa3caee28e1622024c885369d876a149 100644 (file)
 #include <linux/slab.h>
 #include <linux/highmem.h>     /* pte_offset_map => kmap_atomic */
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/pgalloc.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/mxcc.h>
 #include <asm/mbus.h>
@@ -55,30 +56,21 @@ static pgprot_t dvma_prot;          /* Consistent mapping pte flags */
 #define IOPERM        (IOPTE_CACHE | IOPTE_WRITE | IOPTE_VALID)
 #define MKIOPTE(pfn, perm) (((((pfn)<<8) & IOPTE_PAGE) | (perm)) & ~IOPTE_WAZ)
 
-void __init
-iommu_init(int iommund, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
-       unsigned int impl, vers;
-       unsigned long tmp;
        struct iommu_struct *iommu;
-       struct linux_prom_registers iommu_promregs[PROMREG_MAX];
-       struct resource r;
+       unsigned int impl, vers;
        unsigned long *bitmap;
+       unsigned long tmp;
 
        iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC);
        if (!iommu) {
                prom_printf("Unable to allocate iommu structure\n");
                prom_halt();
        }
-       iommu->regs = NULL;
-       if (prom_getproperty(iommund, "reg", (void *) iommu_promregs,
-                        sizeof(iommu_promregs)) != -1) {
-               memset(&r, 0, sizeof(r));
-               r.flags = iommu_promregs[0].which_io;
-               r.start = iommu_promregs[0].phys_addr;
-               iommu->regs = (struct iommu_regs *)
-                       sbus_ioremap(&r, 0, PAGE_SIZE * 3, "iommu_regs");
-       }
+
+       iommu->regs = of_ioremap(&op->resource[0], 0, PAGE_SIZE * 3,
+                                "iommu_regs");
        if (!iommu->regs) {
                prom_printf("Cannot map IOMMU registers\n");
                prom_halt();
@@ -128,13 +120,29 @@ iommu_init(int iommund, struct sbus_bus *sbus)
        else
                iommu->usemap.num_colors = 1;
 
-       printk("IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
-           impl, vers, iommu->page_table,
-           (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+       printk(KERN_INFO "IOMMU: impl %d vers %d table 0x%p[%d B] map [%d b]\n",
+              impl, vers, iommu->page_table,
+              (int)(IOMMU_NPTES*sizeof(iopte_t)), (int)IOMMU_NPTES);
+
+       op->dev.archdata.iommu = iommu;
+}
+
+static int __init iommu_init(void)
+{
+       struct device_node *dp;
+
+       for_each_node_by_name(dp, "iommu") {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               sbus_iommu_init(op);
+               of_propagate_archdata(op);
+       }
 
-       sbus->ofdev.dev.archdata.iommu = iommu;
+       return 0;
 }
 
+subsys_initcall(iommu_init);
+
 /* This begs to be btfixup-ed by srmmu. */
 /* Flush the iotlb entries to ram. */
 /* This could be better if we didn't have to flush whole pages. */
@@ -164,9 +172,9 @@ static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte)
        }
 }
 
-static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
+static u32 iommu_get_one(struct device *dev, struct page *page, int npages)
 {
-       struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        int ioptex;
        iopte_t *iopte, *iopte0;
        unsigned int busa, busa0;
@@ -194,8 +202,7 @@ static u32 iommu_get_one(struct page *page, int npages, struct sbus_bus *sbus)
        return busa0;
 }
 
-static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
-    struct sbus_bus *sbus)
+static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len)
 {
        unsigned long off;
        int npages;
@@ -205,22 +212,22 @@ static u32 iommu_get_scsi_one(char *vaddr, unsigned int len,
        off = (unsigned long)vaddr & ~PAGE_MASK;
        npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
        page = virt_to_page((unsigned long)vaddr & PAGE_MASK);
-       busa = iommu_get_one(page, npages, sbus);
+       busa = iommu_get_one(dev, page, npages);
        return busa + off;
 }
 
-static __u32 iommu_get_scsi_one_noflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len)
 {
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_gflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len)
 {
        flush_page_for_dma(0);
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sbus_bus *sbus)
+static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned long len)
 {
        unsigned long page = ((unsigned long) vaddr) & PAGE_MASK;
 
@@ -228,23 +235,23 @@ static __u32 iommu_get_scsi_one_pflush(char *vaddr, unsigned long len, struct sb
                flush_page_for_dma(page);
                page += PAGE_SIZE;
        }
-       return iommu_get_scsi_one(vaddr, len, sbus);
+       return iommu_get_scsi_one(dev, vaddr, len);
 }
 
-static void iommu_get_scsi_sgl_noflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
@@ -252,13 +259,13 @@ static void iommu_get_scsi_sgl_gflush(struct scatterlist *sg, int sz, struct sbu
        while (sz != 0) {
                --sz;
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_get_scsi_sgl_pflush(struct device *dev, struct scatterlist *sg, int sz)
 {
        unsigned long page, oldpage = 0;
        int n, i;
@@ -283,15 +290,15 @@ static void iommu_get_scsi_sgl_pflush(struct scatterlist *sg, int sz, struct sbu
                        }
                }
 
-               sg->dvma_address = iommu_get_one(sg_page(sg), n, sbus) + sg->offset;
+               sg->dvma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset;
                sg->dvma_length = (__u32) sg->length;
                sg = sg_next(sg);
        }
 }
 
-static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
+static void iommu_release_one(struct device *dev, u32 busa, int npages)
 {
-       struct iommu_struct *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        int ioptex;
        int i;
 
@@ -305,17 +312,17 @@ static void iommu_release_one(u32 busa, int npages, struct sbus_bus *sbus)
        bit_map_clear(&iommu->usemap, ioptex, npages);
 }
 
-static void iommu_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
+static void iommu_release_scsi_one(struct device *dev, __u32 vaddr, unsigned long len)
 {
        unsigned long off;
        int npages;
 
        off = vaddr & ~PAGE_MASK;
        npages = (off + len + PAGE_SIZE-1) >> PAGE_SHIFT;
-       iommu_release_one(vaddr & PAGE_MASK, npages, sbus);
+       iommu_release_one(dev, vaddr & PAGE_MASK, npages);
 }
 
-static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void iommu_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        int n;
 
@@ -323,18 +330,18 @@ static void iommu_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_b
                --sz;
 
                n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT;
-               iommu_release_one(sg->dvma_address & PAGE_MASK, n, sbus);
+               iommu_release_one(dev, sg->dvma_address & PAGE_MASK, n);
                sg->dvma_address = 0x21212121;
                sg = sg_next(sg);
        }
 }
 
 #ifdef CONFIG_SBUS
-static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int iommu_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+                             unsigned long addr, int len)
 {
+       struct iommu_struct *iommu = dev->archdata.iommu;
        unsigned long page, end;
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
        iopte_t *iopte = iommu->page_table;
        iopte_t *first;
        int ioptex;
@@ -397,9 +404,9 @@ static int iommu_map_dma_area(dma_addr_t *pba, unsigned long va,
        return 0;
 }
 
-static void iommu_unmap_dma_area(unsigned long busa, int len)
+static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
+       struct iommu_struct *iommu = dev->archdata.iommu;
        iopte_t *iopte = iommu->page_table;
        unsigned long end;
        int ioptex = (busa - iommu->start) >> PAGE_SHIFT;
@@ -417,15 +424,6 @@ static void iommu_unmap_dma_area(unsigned long busa, int len)
        iommu_invalidate(iommu->regs);
        bit_map_clear(&iommu->usemap, ioptex, len >> PAGE_SHIFT);
 }
-
-static struct page *iommu_translate_dvma(unsigned long busa)
-{
-       struct iommu_struct *iommu = sbus_root->ofdev.dev.archdata.iommu;
-       iopte_t *iopte = iommu->page_table;
-
-       iopte += ((busa - iommu->start) >> PAGE_SHIFT);
-       return pfn_to_page((iopte_val(*iopte) & IOPTE_PAGE) >> (PAGE_SHIFT-4));
-}
 #endif
 
 static char *iommu_lockarea(char *vaddr, unsigned long len)
@@ -461,7 +459,6 @@ void __init ld_mmu_iommu(void)
 #ifdef CONFIG_SBUS
        BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, iommu_translate_dvma, BTFIXUPCALL_NORM);
 #endif
 
        if (viking_mxcc_present || srmmu_modtype == HyperSparc) {
diff --git a/arch/sparc/mm/nosrmmu.c b/arch/sparc/mm/nosrmmu.c
deleted file mode 100644 (file)
index 3701f70..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * nosrmmu.c: This file is a bunch of dummies for sun4 compiles, 
- *         so that it does not need srmmu and avoid ifdefs.
- *
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <asm/mbus.h>
-#include <asm/sbus.h>
-
-static char shouldnothappen[] __initdata = "SUN4 kernel can only run on SUN4\n";
-
-enum mbus_module srmmu_modtype;
-void *srmmu_nocache_pool;
-
-int vac_cache_size = 0;
-
-static void __init should_not_happen(void)
-{
-       prom_printf(shouldnothappen);
-       prom_halt();
-}
-
-void __init srmmu_frob_mem_map(unsigned long start_mem)
-{
-       should_not_happen();
-}
-
-unsigned long __init srmmu_paging_init(unsigned long start_mem, unsigned long end_mem)
-{
-       should_not_happen();
-       return 0;
-}
-
-void __init ld_mmu_srmmu(void)
-{
-       should_not_happen();
-}
-
-void srmmu_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly)
-{
-}
-
-void srmmu_unmapioaddr(unsigned long virt_addr)
-{
-}
-
-__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
-{
-       return 0;
-}
-
-__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
-{
-       return 0;
-}
index ee30462598fc72b763da88077b72438be730cbf4..6a5d7cabc04450eb10dcb4f75c792aa36838d584 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/mbus.h>
 #include <asm/cache.h>
 #include <asm/oplib.h>
-#include <asm/sbus.h>
 #include <asm/asi.h>
 #include <asm/msi.h>
 #include <asm/mmu_context.h>
index d1782f6368beeadf9afbc9936b3b8e39da75db90..fe65aeeb3947a70fafb900fb94014311f43a59df 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/oplib.h>
 #include <asm/openprom.h>
 #include <asm/mmu_context.h>
-#include <asm/sun4paddr.h>
 #include <asm/highmem.h>
 #include <asm/btfixup.h>
 #include <asm/cacheflush.h>
@@ -52,15 +51,11 @@ extern int num_segmaps, num_contexts;
 
 extern unsigned long page_kernel;
 
-#ifdef CONFIG_SUN4
-#define SUN4C_VAC_SIZE sun4c_vacinfo.num_bytes
-#else
 /* That's it, we prom_halt() on sun4c if the cache size is something other than 65536.
  * So let's save some cycles and just use that everywhere except for that bootup
  * sanity check.
  */
 #define SUN4C_VAC_SIZE 65536
-#endif
 
 #define SUN4C_KERNEL_BUCKETS 32
 
@@ -285,75 +280,32 @@ void __init sun4c_probe_vac(void)
 {
        sun4c_disable_vac();
 
-       if (ARCH_SUN4) {
-               switch (idprom->id_machtype) {
-
-               case (SM_SUN4|SM_4_110):
-                       sun4c_vacinfo.type = VAC_NONE;
-                       sun4c_vacinfo.num_bytes = 0;
-                       sun4c_vacinfo.linesize = 0;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       prom_printf("No VAC. Get some bucks and buy a real computer.");
-                       prom_halt();
-                       break;
-
-               case (SM_SUN4|SM_4_260):
-                       sun4c_vacinfo.type = VAC_WRITE_BACK;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 16;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               case (SM_SUN4|SM_4_330):
-                       sun4c_vacinfo.type = VAC_WRITE_THROUGH;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 16;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               case (SM_SUN4|SM_4_470):
-                       sun4c_vacinfo.type = VAC_WRITE_BACK;
-                       sun4c_vacinfo.num_bytes = 128 * 1024;
-                       sun4c_vacinfo.linesize = 32;
-                       sun4c_vacinfo.do_hwflushes = 0;
-                       break;
-
-               default:
-                       prom_printf("Cannot initialize VAC - weird sun4 model idprom->id_machtype = %d", idprom->id_machtype);
-                       prom_halt();
-               };
+       if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               /* PROM on SS1 lacks this info, to be super safe we
+                * hard code it here since this arch is cast in stone.
+                */
+               sun4c_vacinfo.num_bytes = 65536;
+               sun4c_vacinfo.linesize = 16;
        } else {
-               sun4c_vacinfo.type = VAC_WRITE_THROUGH;
+               sun4c_vacinfo.num_bytes =
+                prom_getintdefault(prom_root_node, "vac-size", 65536);
+               sun4c_vacinfo.linesize =
+                prom_getintdefault(prom_root_node, "vac-linesize", 16);
+       }
+       sun4c_vacinfo.do_hwflushes =
+        prom_getintdefault(prom_root_node, "vac-hwflush", 0);
 
-               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-                       /* PROM on SS1 lacks this info, to be super safe we
-                        * hard code it here since this arch is cast in stone.
-                        */
-                       sun4c_vacinfo.num_bytes = 65536;
-                       sun4c_vacinfo.linesize = 16;
-               } else {
-                       sun4c_vacinfo.num_bytes =
-                        prom_getintdefault(prom_root_node, "vac-size", 65536);
-                       sun4c_vacinfo.linesize =
-                        prom_getintdefault(prom_root_node, "vac-linesize", 16);
-               }
+       if (sun4c_vacinfo.do_hwflushes == 0)
                sun4c_vacinfo.do_hwflushes =
-                prom_getintdefault(prom_root_node, "vac-hwflush", 0);
-
-               if (sun4c_vacinfo.do_hwflushes == 0)
-                       sun4c_vacinfo.do_hwflushes =
-                        prom_getintdefault(prom_root_node, "vac_hwflush", 0);
+                prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
-               if (sun4c_vacinfo.num_bytes != 65536) {
-                       prom_printf("WEIRD Sun4C VAC cache size, "
-                                   "tell sparclinux@vger.kernel.org");
-                       prom_halt();
-               }
+       if (sun4c_vacinfo.num_bytes != 65536) {
+               prom_printf("WEIRD Sun4C VAC cache size, "
+                           "tell sparclinux@vger.kernel.org");
+               prom_halt();
        }
 
-       sun4c_vacinfo.num_lines =
-               (sun4c_vacinfo.num_bytes / sun4c_vacinfo.linesize);
        switch (sun4c_vacinfo.linesize) {
        case 16:
                sun4c_vacinfo.log2lsize = 4;
@@ -447,49 +399,18 @@ static void __init patch_kernel_fault_handler(void)
 
 static void __init sun4c_probe_mmu(void)
 {
-       if (ARCH_SUN4) {
-               switch (idprom->id_machtype) {
-               case (SM_SUN4|SM_4_110):
-                       prom_printf("No support for 4100 yet\n");
-                       prom_halt();
-                       num_segmaps = 256;
-                       num_contexts = 8;
-                       break;
-
-               case (SM_SUN4|SM_4_260):
-                       /* should be 512 segmaps. when it get fixed */
-                       num_segmaps = 256;
-                       num_contexts = 16;
-                       break;
-
-               case (SM_SUN4|SM_4_330):
-                       num_segmaps = 256;
-                       num_contexts = 16;
-                       break;
-
-               case (SM_SUN4|SM_4_470):
-                       /* should be 1024 segmaps. when it get fixed */
-                       num_segmaps = 256;
-                       num_contexts = 64;
-                       break;
-               default:
-                       prom_printf("Invalid SUN4 model\n");
-                       prom_halt();
-               };
+       if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+           (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+               /* Hardcode these just to be safe, PROM on SS1 does
+               * not have this info available in the root node.
+               */
+               num_segmaps = 128;
+               num_contexts = 8;
        } else {
-               if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
-                   (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
-                       /* Hardcode these just to be safe, PROM on SS1 does
-                       * not have this info available in the root node.
-                       */
-                       num_segmaps = 128;
-                       num_contexts = 8;
-               } else {
-                       num_segmaps =
-                           prom_getintdefault(prom_root_node, "mmu-npmg", 128);
-                       num_contexts =
-                           prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
-               }
+               num_segmaps =
+                   prom_getintdefault(prom_root_node, "mmu-npmg", 128);
+               num_contexts =
+                   prom_getintdefault(prom_root_node, "mmu-nctx", 0x8);
        }
        patch_kernel_fault_handler();
 }
@@ -501,18 +422,14 @@ void __init sun4c_probe_memerr_reg(void)
        int node;
        struct linux_prom_registers regs[1];
 
-       if (ARCH_SUN4) {
-               sun4c_memerr_reg = ioremap(sun4_memreg_physaddr, PAGE_SIZE);
-       } else {
-               node = prom_getchild(prom_root_node);
-               node = prom_searchsiblings(prom_root_node, "memory-error");
-               if (!node)
-                       return;
-               if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
-                       return;
-               /* hmm I think regs[0].which_io is zero here anyways */
-               sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
-       }
+       node = prom_getchild(prom_root_node);
+       node = prom_searchsiblings(prom_root_node, "memory-error");
+       if (!node)
+               return;
+       if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0)
+               return;
+       /* hmm I think regs[0].which_io is zero here anyways */
+       sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size);
 }
 
 static inline void sun4c_init_ss2_cache_bug(void)
@@ -521,7 +438,6 @@ static inline void sun4c_init_ss2_cache_bug(void)
 
        if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) ||
            (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) ||
-           (idprom->id_machtype == (SM_SUN4 | SM_4_330)) ||
            (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) {
                /* Whee.. */
                printk("SS2 cache bug detected, uncaching trap table page\n");
@@ -532,8 +448,8 @@ static inline void sun4c_init_ss2_cache_bug(void)
 }
 
 /* Addr is always aligned on a page boundary for us already. */
-static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
-    unsigned long addr, int len)
+static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va,
+                             unsigned long addr, int len)
 {
        unsigned long page, end;
 
@@ -555,14 +471,7 @@ static int sun4c_map_dma_area(dma_addr_t *pba, unsigned long va,
        return 0;
 }
 
-static struct page *sun4c_translate_dvma(unsigned long busa)
-{
-       /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
-       unsigned long pte = sun4c_get_pte(busa);
-       return pfn_to_page(pte & SUN4C_PFN_MASK);
-}
-
-static void sun4c_unmap_dma_area(unsigned long busa, int len)
+static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len)
 {
        /* Fortunately for us, bus_addr == uncached_virt in sun4c. */
        /* XXX Implement this */
@@ -624,11 +533,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
 {
        unsigned long vaddr;
        unsigned char pseg, ctx;
-#ifdef CONFIG_SUN4
-       /* sun4/110 and 260 have no kadb. */
-       if ((idprom->id_machtype != (SM_SUN4 | SM_4_260)) && 
-           (idprom->id_machtype != (SM_SUN4 | SM_4_110))) {
-#endif
+
        for (vaddr = KADB_DEBUGGER_BEGVM;
             vaddr < LINUX_OPPROM_ENDVM;
             vaddr += SUN4C_REAL_PGDIR_SIZE) {
@@ -640,9 +545,7 @@ static inline void sun4c_init_map_kernelprom(unsigned long kernel_end)
                        fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0);
                }
        }
-#ifdef CONFIG_SUN4
-       }
-#endif
+
        for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) {
                pseg = sun4c_get_segmap(vaddr);
                mmu_entry_pool[pseg].locked = 1;
@@ -1048,14 +951,10 @@ static struct thread_info *sun4c_alloc_thread_info(void)
         * so we must flush the cache to guarantee consistency.
         */
        sun4c_flush_page(pages);
-#ifndef CONFIG_SUN4    
        sun4c_flush_page(pages + PAGE_SIZE);
-#endif
 
        sun4c_put_pte(addr, BUCKET_PTE(pages));
-#ifndef CONFIG_SUN4    
        sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE));
-#endif
 
 #ifdef CONFIG_DEBUG_STACK_USAGE
        memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER);
@@ -1072,13 +971,11 @@ static void sun4c_free_thread_info(struct thread_info *ti)
 
        /* We are deleting a mapping, so the flush here is mandatory. */
        sun4c_flush_page(tiaddr);
-#ifndef CONFIG_SUN4    
        sun4c_flush_page(tiaddr + PAGE_SIZE);
-#endif
+
        sun4c_put_pte(tiaddr, 0);
-#ifndef CONFIG_SUN4    
        sun4c_put_pte(tiaddr + PAGE_SIZE, 0);
-#endif
+
        sun4c_bucket[entry] = BUCKET_EMPTY;
        if (entry < sun4c_lowbucket_avail)
                sun4c_lowbucket_avail = entry;
@@ -1211,7 +1108,7 @@ static void sun4c_unlockarea(char *vaddr, unsigned long size)
  * by implication and fool the page locking code above
  * if passed to by mistake.
  */
-static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus *sbus)
+static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len)
 {
        unsigned long page;
 
@@ -1223,7 +1120,7 @@ static __u32 sun4c_get_scsi_one(char *bufptr, unsigned long len, struct sbus_bus
        return (__u32)sun4c_lockarea(bufptr, len);
 }
 
-static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        while (sz != 0) {
                --sz;
@@ -1233,14 +1130,14 @@ static void sun4c_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *
        }
 }
 
-static void sun4c_release_scsi_one(__u32 bufptr, unsigned long len, struct sbus_bus *sbus)
+static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len)
 {
        if (bufptr < sun4c_iobuffer_start)
                return; /* On kernel stack or similar, see above */
        sun4c_unlockarea((char *)bufptr, len);
 }
 
-static void sun4c_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
+static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz)
 {
        while (sz != 0) {
                --sz;
@@ -2263,7 +2160,6 @@ void __init ld_mmu_sun4c(void)
 
        BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(mmu_translate_dvma, sun4c_translate_dvma, BTFIXUPCALL_NORM);
 
        BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM);
index 7f5eacfcfbcfbd4604fe716f8b147b461096a621..8f7e18546c974f6ba8fec1c6ec8befcc21d5d30d 100644 (file)
@@ -4,5 +4,3 @@
 
 lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
         palloc.o ranges.o segment.o console.o printf.o tree.o
-
-lib-$(CONFIG_SUN4) += sun4prom.o
index 5a35c768ff7cb2f3a70a52f5c79010224cefe016..916831da7e67327c818da9a0ec864aabb5411a4c 100644 (file)
@@ -6,15 +6,12 @@
 
 #include <linux/string.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 #include <linux/init.h>
 
 #define BARG_LEN  256
 static char barg_buf[BARG_LEN] = { 0 };
 static char fetched __initdata = 0;
 
-extern linux_sun4_romvec *sun4_romvec;
-
 char * __init
 prom_getbootargs(void)
 {
@@ -28,7 +25,6 @@ prom_getbootargs(void)
 
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                cp = barg_buf;
                /* Start from 1 and go over fd(0,0,0)kernel */
                for(iter = 1; iter < 8; iter++) {
index 790057a34616357753e31539b5c27867f04a90e5..b3075d73fc19e7f2bf765a4cff144aa27683334b 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/system.h>
 #include <linux/string.h>
@@ -30,7 +29,6 @@ prom_nbgetchar(void)
        spin_lock_irqsave(&prom_lock, flags);
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                i = (*(romvec->pv_nbgetchar))();
                break;
        case PROM_V2:
@@ -63,7 +61,6 @@ prom_nbputchar(char c)
        spin_lock_irqsave(&prom_lock, flags);
        switch(prom_vers) {
        case PROM_V0:
-       case PROM_SUN4:
                i = (*(romvec->pv_nbputchar))(c);
                break;
        case PROM_V2:
index 729f87066945c2d7ddb713700650dd9c90062c0a..873217c6d8234a7396aef8a36d07f706bafcba9d 100644 (file)
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
-#include <asm/sun4prom.h>
 
 struct linux_romvec *romvec;
 enum prom_major_version prom_vers;
 unsigned int prom_rev, prom_prev;
-linux_sun4_romvec *sun4_romvec;
 
 /* The root node of the prom device tree. */
 int prom_root_node;
@@ -34,10 +32,6 @@ extern void prom_ranges_init(void);
 
 void __init prom_init(struct linux_romvec *rp)
 {
-#ifdef CONFIG_SUN4
-       extern struct linux_romvec *sun4_prom_init(void);
-       rp = sun4_prom_init();
-#endif
        romvec = rp;
 
        switch(romvec->pv_romvers) {
@@ -50,9 +44,6 @@ void __init prom_init(struct linux_romvec *rp)
        case 3:
                prom_vers = PROM_V3;
                break;
-       case 40:
-               prom_vers = PROM_SUN4;
-               break;
        default:
                prom_printf("PROMLIB: Bad PROM version %d\n",
                            romvec->pv_romvers);
@@ -76,11 +67,8 @@ void __init prom_init(struct linux_romvec *rp)
 
        prom_ranges_init();
 
-#ifndef CONFIG_SUN4
-       /* SUN4 prints this in sun4_prom_init */
        printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
               romvec->pv_romvers, prom_rev);
-#endif
 
        /* Initialization successful. */
        return;
index 947f047dc95a67173d0072653052f92187b74325..fac7899a29c39042ab0a69be31c6cc0bc1b8fb32 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/init.h>
 
 #include <asm/openprom.h>
-#include <asm/sun4prom.h>
 #include <asm/oplib.h>
 #include <asm/page.h>
 
@@ -46,15 +45,6 @@ static int __init prom_meminit_v2(void)
        return num_ents;
 }
 
-static int __init prom_meminit_sun4(void)
-{
-#ifdef CONFIG_SUN4
-       sp_banks[0].base_addr = 0;
-       sp_banks[0].num_bytes = *(sun4_romvec->memoryavail);
-#endif
-       return 1;
-}
-
 static int sp_banks_cmp(const void *a, const void *b)
 {
        const struct sparc_phys_banks *x = a, *y = b;
@@ -81,10 +71,6 @@ void __init prom_meminit(void)
                num_ents = prom_meminit_v2();
                break;
 
-       case PROM_SUN4:
-               num_ents = prom_meminit_sun4();
-               break;
-
        default:
                break;
        }
index f9b7def35f6eacbca62590c32a086c64e117f37d..64579a376419b7b3b1231e0e1080e3e8c7078821 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/types.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX];
diff --git a/arch/sparc/prom/sun4prom.c b/arch/sparc/prom/sun4prom.c
deleted file mode 100644 (file)
index 00390a2..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 1996 The Australian National University.
- * Copyright (C) 1996 Fujitsu Laboratories Limited
- * Copyright (C) 1997 Michael A. Griffith (grif@acm.org)
- * Copyright (C) 1997 Sun Weenie (ko@ko.reno.nv.us)
- * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * 
- * This software may be distributed under the terms of the Gnu
- * Public License version 2 or later
- *
- * fake a really simple Sun prom for the SUN4
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <asm/oplib.h>
-#include <asm/idprom.h> 
-#include <asm/machines.h> 
-#include <asm/sun4prom.h>
-#include <asm/asi.h>
-#include <asm/contregs.h>
-#include <linux/init.h>
-
-static struct linux_romvec sun4romvec;
-static struct idprom sun4_idprom;
-
-struct property {
-       char *name;
-       char *value;
-       int length;
-};
-
-struct node {
-       int level;
-       struct property *properties;
-};
-
-struct property null_properties = { NULL, NULL, -1 };
-
-struct property root_properties[] = {
-       {"device_type", "cpu", 4},
-       {"idprom", (char *)&sun4_idprom, sizeof(struct idprom)},
-       {NULL, NULL, -1}
-};
-
-struct node nodes[] = {
-       { 0, &null_properties }, 
-       { 0, root_properties },
-       { -1,&null_properties }
-};
-
-
-static int no_nextnode(int node)
-{
-       if (nodes[node].level == nodes[node+1].level)
-               return node+1;
-       return -1;
-}
-
-static int no_child(int node)
-{
-       if (nodes[node].level == nodes[node+1].level-1)
-               return node+1;
-       return -1;
-}
-
-static struct property *find_property(int node,char *name)
-{
-       struct property *prop = &nodes[node].properties[0];
-       while (prop && prop->name) {
-               if (strcmp(prop->name,name) == 0) return prop;
-               prop++;
-       }
-       return NULL;
-}
-
-static int no_proplen(int node,char *name)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) return prop->length;
-       return -1;
-}
-
-static int no_getprop(int node,char *name,char *value)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) {
-               memcpy(value,prop->value,prop->length);
-               return 1;
-       }
-       return -1;
-}
-
-static int no_setprop(int node,char *name,char *value,int len)
-{
-       return -1;
-}
-
-static char *no_nextprop(int node,char *name)
-{
-       struct property *prop = find_property(node,name);
-       if (prop) return prop[1].name;
-       return NULL;
-}
-
-static struct linux_nodeops sun4_nodeops = {
-       no_nextnode,
-       no_child,
-       no_proplen,
-       no_getprop,
-       no_setprop,
-       no_nextprop
-};
-       
-static int synch_hook;
-
-struct linux_romvec * __init sun4_prom_init(void)
-{
-       int i;
-       unsigned char x;
-       char *p;
-                                
-       p = (char *)&sun4_idprom;
-       for (i = 0; i < sizeof(sun4_idprom); i++) {
-               __asm__ __volatile__ ("lduba [%1] %2, %0" : "=r" (x) :
-                                     "r" (AC_IDPROM + i), "i" (ASI_CONTROL));
-               *p++ = x;
-       }
-
-       memset(&sun4romvec,0,sizeof(sun4romvec));
-
-       sun4_romvec = (linux_sun4_romvec *) SUN4_PROM_VECTOR;
-
-       sun4romvec.pv_romvers = 40;
-       sun4romvec.pv_nodeops = &sun4_nodeops;
-       sun4romvec.pv_reboot = sun4_romvec->reboot;
-       sun4romvec.pv_abort = sun4_romvec->abortentry;
-       sun4romvec.pv_halt = sun4_romvec->exittomon;
-       sun4romvec.pv_synchook = (void (**)(void))&synch_hook;
-       sun4romvec.pv_setctxt = sun4_romvec->setcxsegmap;
-       sun4romvec.pv_v0bootargs = sun4_romvec->bootParam;
-       sun4romvec.pv_nbgetchar = sun4_romvec->mayget;
-       sun4romvec.pv_nbputchar = sun4_romvec->mayput;
-       sun4romvec.pv_stdin = sun4_romvec->insource;
-       sun4romvec.pv_stdout = sun4_romvec->outsink;
-       
-       /*
-        * We turn on the LEDs to let folks without monitors or
-        * terminals know we booted.   Nothing too fancy now.  They
-        * are all on, except for LED 5, which blinks.   When we
-        * have more time, we can teach the penguin to say "By your
-        * command" or "Activating turbo boost, Michael". :-)
-        */
-       sun4_romvec->setLEDs(NULL);
-       
-       printk("PROMLIB: Old Sun4 boot PROM monitor %s, romvec version %d\n",
-               sun4_romvec->monid,
-               sun4_romvec->romvecversion);
-
-       return &sun4romvec;
-}
index 36b4b7ab9cfb9250684e13874d6582302076d9c2..5446e2a499b13d36e3e50a529e85cd0e91ad5de4 100644 (file)
@@ -18,6 +18,13 @@ config SPARC64
        select HAVE_ARCH_KGDB
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_ARCH_TRACEHOOK
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select RTC_CLASS
+       select RTC_DRV_M48T59
+       select RTC_DRV_CMOS
+       select RTC_DRV_BQ4802
+       select RTC_DRV_SUN4V
+       select RTC_DRV_STARFIRE
 
 config GENERIC_TIME
        bool
@@ -31,6 +38,11 @@ config GENERIC_CLOCKEVENTS
        bool
        default y
 
+config GENERIC_GPIO
+       bool
+       help
+         Generic GPIO API support
+
 config 64BIT
        def_bool y
 
@@ -185,6 +197,17 @@ config US2E_FREQ
 
          If in doubt, say N.
 
+config US3_MC
+       tristate "UltraSPARC-III Memory Controller driver"
+       default y
+       help
+         This adds a driver for the UltraSPARC-III memory controller.
+         Loading this driver allows exact mnemonic strings to be
+         printed in the event of a memory error, so that the faulty DIMM
+         on the motherboard can be matched to the error.
+
+         If in doubt, say Y, as this information can be very useful.
+
 # Global things across all Sun machines.
 config GENERIC_LOCKBREAK
        bool
index b785a395b12f1d1793be9127898866cb6285e289..c7214abc0d84f9b8e2c4c591fc0256e77da1638e 100644 (file)
@@ -7,7 +7,7 @@
 # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
-CHECKFLAGS     += -D__sparc__ -D__sparc_v9__ -m64
+CHECKFLAGS     += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
 
 # Undefine sparc when processing vmlinux.lds - it is used
 # And teach CPP we are doing 64 bit builds (for this case)
index 418b5782096ec709eda315ceb79f5575d50059a6..c0b8009ab196cc4bf32ff517db0aa99896db0101 100644 (file)
@@ -7,16 +7,16 @@ EXTRA_CFLAGS := -Werror
 
 extra-y                := head.o init_task.o vmlinux.lds
 
-obj-y          := process.o setup.o cpu.o idprom.o \
+obj-y          := process.o setup.o cpu.o idprom.o reboot.o \
                   traps.o auxio.o una_asm.o sysfs.o iommu.o \
                   irq.o ptrace.o time.o sys_sparc.o signal.o \
-                  unaligned.o central.o pci.o starfire.o \
-                  power.o sbus.o sparc64_ksyms.o chmc.o \
+                  unaligned.o central.o starfire.o \
+                  power.o sbus.o sparc64_ksyms.o ebus.o \
                   visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
 
 obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI)       += ebus.o pci_common.o \
+obj-$(CONFIG_PCI)       += pci.o pci_common.o psycho_common.o \
                            pci_psycho.o pci_sabre.o pci_schizo.o \
                            pci_sun4v.o pci_sun4v_asm.o pci_fire.o
 obj-$(CONFIG_PCI_MSI)  += pci_msi.o
@@ -25,6 +25,7 @@ obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
 obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC) += chmc.o
 obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
 obj-$(CONFIG_AUDIT) += audit.o
index dd5c7bf87619b1ef2a3f17fb4adffa1ee7911f26..858beda86524c96fc7c0dfba4b91736104ff4798 100644 (file)
@@ -109,7 +109,7 @@ void auxio_set_lte(int on)
        }
 }
 
-static struct of_device_id auxio_match[] = {
+static struct of_device_id __initdata auxio_match[] = {
        {
                .name = "auxio",
        },
index f2e87d0d7e1d7ab2c17020443d39b09dc9de193c..05f1c916db066057653199aca45156b33398b341 100644 (file)
 /* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
  *
- * Copyright (C) 1997, 1999 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/bootmem.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
 
-#include <asm/page.h>
 #include <asm/fhc.h>
-#include <asm/starfire.h>
-
-static struct linux_central *central_bus = NULL;
-static struct linux_fhc *fhc_list = NULL;
+#include <asm/upa.h>
+
+struct clock_board {
+       void __iomem            *clock_freq_regs;
+       void __iomem            *clock_regs;
+       void __iomem            *clock_ver_reg;
+       int                     num_slots;
+       struct resource         leds_resource;
+       struct platform_device  leds_pdev;
+};
+
+struct fhc {
+       void __iomem            *pregs;
+       bool                    central;
+       bool                    jtag_master;
+       int                     board_num;
+       struct resource         leds_resource;
+       struct platform_device  leds_pdev;
+};
+
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
+{
+       u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
 
-#define IS_CENTRAL_FHC(__fhc)  ((__fhc) == central_bus->child)
+       switch (reg) {
+       case 0x40:
+               return 16;
 
-static void central_probe_failure(int line)
-{
-       prom_printf("CENTRAL: Critical device probe failure at central.c:%d\n",
-                   line);
-       prom_halt();
-}
+       case 0xc0:
+               return 8;
 
-static void central_ranges_init(struct linux_central *central)
-{
-       struct device_node *dp = central->prom_node;
-       const void *pval;
-       int len;
-       
-       central->num_central_ranges = 0;
-       pval = of_get_property(dp, "ranges", &len);
-       if (pval) {
-               memcpy(central->central_ranges, pval, len);
-               central->num_central_ranges =
-                       (len / sizeof(struct linux_prom_ranges));
+       case 0x80:
+               reg = 0;
+               if (p->clock_ver_reg)
+                       reg = upa_readb(p->clock_ver_reg);
+               if (reg) {
+                       if (reg & 0x80)
+                               return 4;
+                       else
+                               return 5;
+               }
+               /* Fallthrough */
+       default:
+               return 4;
        }
 }
 
-static void fhc_ranges_init(struct linux_fhc *fhc)
+static int __devinit clock_board_probe(struct of_device *op,
+                                      const struct of_device_id *match)
 {
-       struct device_node *dp = fhc->prom_node;
-       const void *pval;
-       int len;
-       
-       fhc->num_fhc_ranges = 0;
-       pval = of_get_property(dp, "ranges", &len);
-       if (pval) {
-               memcpy(fhc->fhc_ranges, pval, len);
-               fhc->num_fhc_ranges =
-                       (len / sizeof(struct linux_prom_ranges));
-       }
-}
+       struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
 
-/* Range application routines are exported to various drivers,
- * so do not __init this.
- */
-static void adjust_regs(struct linux_prom_registers *regp, int nregs,
-                       struct linux_prom_ranges *rangep, int nranges)
-{
-       int regc, rngc;
-
-       for (regc = 0; regc < nregs; regc++) {
-               for (rngc = 0; rngc < nranges; rngc++)
-                       if (regp[regc].which_io == rangep[rngc].ot_child_space)
-                               break; /* Fount it */
-               if (rngc == nranges) /* oops */
-                       central_probe_failure(__LINE__);
-               regp[regc].which_io = rangep[rngc].ot_parent_space;
-               regp[regc].phys_addr -= rangep[rngc].ot_child_base;
-               regp[regc].phys_addr += rangep[rngc].ot_parent_base;
+       if (!p) {
+               printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+               goto out;
        }
-}
 
-/* Apply probed fhc ranges to registers passed, if no ranges return. */
-static void apply_fhc_ranges(struct linux_fhc *fhc,
-                            struct linux_prom_registers *regs,
-                            int nregs)
-{
-       if (fhc->num_fhc_ranges)
-               adjust_regs(regs, nregs, fhc->fhc_ranges,
-                           fhc->num_fhc_ranges);
-}
+       p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
+                                       resource_size(&op->resource[0]),
+                                       "clock_board_freq");
+       if (!p->clock_freq_regs) {
+               printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
+               goto out_free;
+       }
 
-/* Apply probed central ranges to registers passed, if no ranges return. */
-static void apply_central_ranges(struct linux_central *central,
-                                struct linux_prom_registers *regs, int nregs)
-{
-       if (central->num_central_ranges)
-               adjust_regs(regs, nregs, central->central_ranges,
-                           central->num_central_ranges);
-}
+       p->clock_regs = of_ioremap(&op->resource[1], 0,
+                                  resource_size(&op->resource[1]),
+                                  "clock_board_regs");
+       if (!p->clock_regs) {
+               printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
+               goto out_unmap_clock_freq_regs;
+       }
 
-static void * __init central_alloc_bootmem(unsigned long size)
-{
-       void *ret;
+       if (op->resource[2].flags) {
+               p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
+                                             resource_size(&op->resource[2]),
+                                             "clock_ver_reg");
+               if (!p->clock_ver_reg) {
+                       printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
+                       goto out_unmap_clock_regs;
+               }
+       }
 
-       ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
-       if (ret != NULL)
-               memset(ret, 0, size);
+       p->num_slots = clock_board_calc_nslots(p);
 
-       return ret;
-}
+       p->leds_resource.start = (unsigned long)
+               (p->clock_regs + CLOCK_CTRL);
+       p->leds_resource.end = p->leds_resource.end;
+       p->leds_resource.name = "leds";
 
-static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
-{
-       unsigned long ret = ((unsigned long) r->which_io) << 32;
+       p->leds_pdev.name = "sunfire-clockboard-leds";
+       p->leds_pdev.resource = &p->leds_resource;
+       p->leds_pdev.num_resources = 1;
+       p->leds_pdev.dev.parent = &op->dev;
 
-       return ret | (unsigned long) r->phys_addr;
-}
-
-static void __init probe_other_fhcs(void)
-{
-       struct device_node *dp;
-       const struct linux_prom64_registers *fpregs;
-
-       for_each_node_by_name(dp, "fhc") {
-               struct linux_fhc *fhc;
-               int board;
-               u32 tmp;
-
-               if (dp->parent &&
-                   dp->parent->parent != NULL)
-                       continue;
-
-               fhc = (struct linux_fhc *)
-                       central_alloc_bootmem(sizeof(struct linux_fhc));
-               if (fhc == NULL)
-                       central_probe_failure(__LINE__);
-
-               /* Link it into the FHC chain. */
-               fhc->next = fhc_list;
-               fhc_list = fhc;
-
-               /* Toplevel FHCs have no parent. */
-               fhc->parent = NULL;
-               
-               fhc->prom_node = dp;
-               fhc_ranges_init(fhc);
-
-               /* Non-central FHC's have 64-bit OBP format registers. */
-               fpregs = of_get_property(dp, "reg", NULL);
-               if (!fpregs)
-                       central_probe_failure(__LINE__);
-
-               /* Only central FHC needs special ranges applied. */
-               fhc->fhc_regs.pregs = fpregs[0].phys_addr;
-               fhc->fhc_regs.ireg = fpregs[1].phys_addr;
-               fhc->fhc_regs.ffregs = fpregs[2].phys_addr;
-               fhc->fhc_regs.sregs = fpregs[3].phys_addr;
-               fhc->fhc_regs.uregs = fpregs[4].phys_addr;
-               fhc->fhc_regs.tregs = fpregs[5].phys_addr;
-
-               board = of_getintprop_default(dp, "board#", -1);
-               fhc->board = board;
-
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_JCTRL);
-               if ((tmp & FHC_JTAG_CTRL_MENAB) != 0)
-                       fhc->jtag_master = 1;
-               else
-                       fhc->jtag_master = 0;
-
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-               printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] %s\n",
-                      board,
-                      (tmp & FHC_ID_VERS) >> 28,
-                      (tmp & FHC_ID_PARTID) >> 12,
-                      (tmp & FHC_ID_MANUF) >> 1,
-                      (fhc->jtag_master ? "(JTAG Master)" : ""));
-               
-               /* This bit must be set in all non-central FHC's in
-                * the system.  When it is clear, this identifies
-                * the central board.
-                */
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-               tmp |= FHC_CONTROL_IXIST;
-               upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       err = platform_device_register(&p->leds_pdev);
+       if (err) {
+               printk(KERN_ERR "clock_board: Could not register LEDS "
+                      "platform device\n");
+               goto out_unmap_clock_ver_reg;
        }
-}
 
-static void probe_clock_board(struct linux_central *central,
-                             struct linux_fhc *fhc,
-                             struct device_node *fp)
-{
-       struct device_node *dp;
-       struct linux_prom_registers cregs[3];
-       const struct linux_prom_registers *pr;
-       int nslots, tmp, nregs;
-
-       dp = fp->child;
-       while (dp) {
-               if (!strcmp(dp->name, "clock-board"))
-                       break;
-               dp = dp->sibling;
-       }
-       if (!dp)
-               central_probe_failure(__LINE__);
+       printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+              p->num_slots);
 
-       pr = of_get_property(dp, "reg", &nregs);
-       if (!pr)
-               central_probe_failure(__LINE__);
+       err = 0;
+out:
+       return err;
 
-       memcpy(cregs, pr, nregs);
-       nregs /= sizeof(struct linux_prom_registers);
+out_unmap_clock_ver_reg:
+       if (p->clock_ver_reg)
+               of_iounmap(&op->resource[2], p->clock_ver_reg,
+                          resource_size(&op->resource[2]));
 
-       apply_fhc_ranges(fhc, &cregs[0], nregs);
-       apply_central_ranges(central, &cregs[0], nregs);
-       central->cfreg = prom_reg_to_paddr(&cregs[0]);
-       central->clkregs = prom_reg_to_paddr(&cregs[1]);
+out_unmap_clock_regs:
+       of_iounmap(&op->resource[1], p->clock_regs,
+                  resource_size(&op->resource[1]));
 
-       if (nregs == 2)
-               central->clkver = 0UL;
-       else
-               central->clkver = prom_reg_to_paddr(&cregs[2]);
+out_unmap_clock_freq_regs:
+       of_iounmap(&op->resource[0], p->clock_freq_regs,
+                  resource_size(&op->resource[0]));
 
-       tmp = upa_readb(central->clkregs + CLOCK_STAT1);
-       tmp &= 0xc0;
-       switch(tmp) {
-       case 0x40:
-               nslots = 16;
-               break;
-       case 0xc0:
-               nslots = 8;
-               break;
-       case 0x80:
-               if (central->clkver != 0UL &&
-                  upa_readb(central->clkver) != 0) {
-                       if ((upa_readb(central->clkver) & 0x80) != 0)
-                               nslots = 4;
-                       else
-                               nslots = 5;
-                       break;
-               }
-       default:
-               nslots = 4;
-               break;
-       };
-       central->slots = nslots;
-       printk("CENTRAL: Detected %d slot Enterprise system. cfreg[%02x] cver[%02x]\n",
-              central->slots, upa_readb(central->cfreg),
-              (central->clkver ? upa_readb(central->clkver) : 0x00));
+out_free:
+       kfree(p);
+       goto out;
 }
 
-static void ZAP(unsigned long iclr, unsigned long imap)
+static struct of_device_id __initdata clock_board_match[] = {
+       {
+               .name = "clock-board",
+       },
+       {},
+};
+
+static struct of_platform_driver clock_board_driver = {
+       .match_table    = clock_board_match,
+       .probe          = clock_board_probe,
+       .driver         = {
+               .name   = "clock_board",
+       },
+};
+
+static int __devinit fhc_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       u32 imap_tmp;
-
-       upa_writel(0, iclr);
-       upa_readl(iclr);
-       imap_tmp = upa_readl(imap);
-       imap_tmp &= ~(0x80000000);
-       upa_writel(imap_tmp, imap);
-       upa_readl(imap);
-}
+       struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+       u32 reg;
 
-static void init_all_fhc_hw(void)
-{
-       struct linux_fhc *fhc;
-
-       for (fhc = fhc_list; fhc != NULL; fhc = fhc->next) {
-               u32 tmp;
-
-               /* Clear all of the interrupt mapping registers
-                * just in case OBP left them in a foul state.
-                */
-               ZAP(fhc->fhc_regs.ffregs + FHC_FFREGS_ICLR,
-                   fhc->fhc_regs.ffregs + FHC_FFREGS_IMAP);
-               ZAP(fhc->fhc_regs.sregs + FHC_SREGS_ICLR,
-                   fhc->fhc_regs.sregs + FHC_SREGS_IMAP);
-               ZAP(fhc->fhc_regs.uregs + FHC_UREGS_ICLR,
-                   fhc->fhc_regs.uregs + FHC_UREGS_IMAP);
-               ZAP(fhc->fhc_regs.tregs + FHC_TREGS_ICLR,
-                   fhc->fhc_regs.tregs + FHC_TREGS_IMAP);
-
-               /* Setup FHC control register. */
-               tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-
-               /* All non-central boards have this bit set. */
-               if (! IS_CENTRAL_FHC(fhc))
-                       tmp |= FHC_CONTROL_IXIST;
-
-               /* For all FHCs, clear the firmware synchronization
-                * line and both low power mode enables.
-                */
-               tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF |
-                        FHC_CONTROL_SLINE);
-
-               upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-               upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       if (!p) {
+               printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+               goto out;
        }
 
-}
+       if (!strcmp(op->node->parent->name, "central"))
+               p->central = true;
 
-void __init central_probe(void)
-{
-       struct linux_prom_registers fpregs[6];
-       const struct linux_prom_registers *pr;
-       struct linux_fhc *fhc;
-       struct device_node *dp, *fp;
-       int err;
-
-       dp = of_find_node_by_name(NULL, "central");
-       if (!dp) {
-               if (this_is_starfire)
-                       starfire_cpu_setup();
-               return;
+       p->pregs = of_ioremap(&op->resource[0], 0,
+                             resource_size(&op->resource[0]),
+                             "fhc_pregs");
+       if (!p->pregs) {
+               printk(KERN_ERR "fhc: Cannot map pregs\n");
+               goto out_free;
        }
 
-       /* Ok we got one, grab some memory for software state. */
-       central_bus = (struct linux_central *)
-               central_alloc_bootmem(sizeof(struct linux_central));
-       if (central_bus == NULL)
-               central_probe_failure(__LINE__);
-
-       fhc = (struct linux_fhc *)
-               central_alloc_bootmem(sizeof(struct linux_fhc));
-       if (fhc == NULL)
-               central_probe_failure(__LINE__);
-
-       /* First init central. */
-       central_bus->child = fhc;
-       central_bus->prom_node = dp;
-       central_ranges_init(central_bus);
-
-       /* And then central's FHC. */
-       fhc->next = fhc_list;
-       fhc_list = fhc;
-
-       fhc->parent = central_bus;
-       fp = dp->child;
-       while (fp) {
-               if (!strcmp(fp->name, "fhc"))
-                       break;
-               fp = fp->sibling;
+       if (p->central) {
+               reg = upa_readl(p->pregs + FHC_PREGS_BSR);
+               p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
+       } else {
+               p->board_num = of_getintprop_default(op->node, "board#", -1);
+               if (p->board_num == -1) {
+                       printk(KERN_ERR "fhc: No board# property\n");
+                       goto out_unmap_pregs;
+               }
+               if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
+                       p->jtag_master = true;
        }
-       if (!fp)
-               central_probe_failure(__LINE__);
-
-       fhc->prom_node = fp;
-       fhc_ranges_init(fhc);
-
-       /* Now, map in FHC register set. */
-       pr = of_get_property(fp, "reg", NULL);
-       if (!pr)
-               central_probe_failure(__LINE__);
-       memcpy(fpregs, pr, sizeof(fpregs));
-
-       apply_central_ranges(central_bus, &fpregs[0], 6);
-       
-       fhc->fhc_regs.pregs = prom_reg_to_paddr(&fpregs[0]);
-       fhc->fhc_regs.ireg = prom_reg_to_paddr(&fpregs[1]);
-       fhc->fhc_regs.ffregs = prom_reg_to_paddr(&fpregs[2]);
-       fhc->fhc_regs.sregs = prom_reg_to_paddr(&fpregs[3]);
-       fhc->fhc_regs.uregs = prom_reg_to_paddr(&fpregs[4]);
-       fhc->fhc_regs.tregs = prom_reg_to_paddr(&fpregs[5]);
-
-       /* Obtain board number from board status register, Central's
-        * FHC lacks "board#" property.
-        */
-       err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_BSR);
-       fhc->board = (((err >> 16) & 0x01) |
-                     ((err >> 12) & 0x0e));
-
-       fhc->jtag_master = 0;
-
-       /* Attach the clock board registers for CENTRAL. */
-       probe_clock_board(central_bus, fhc, fp);
-
-       err = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_ID);
-       printk("FHC(board %d): Version[%x] PartID[%x] Manuf[%x] (CENTRAL)\n",
-              fhc->board,
-              ((err & FHC_ID_VERS) >> 28),
-              ((err & FHC_ID_PARTID) >> 12),
-              ((err & FHC_ID_MANUF) >> 1));
-
-       probe_other_fhcs();
-
-       init_all_fhc_hw();
-}
 
-static inline void fhc_ledblink(struct linux_fhc *fhc, int on)
-{
-       u32 tmp;
+       if (!p->central) {
+               p->leds_resource.start = (unsigned long)
+                       (p->pregs + FHC_PREGS_CTRL);
+               p->leds_resource.end = p->leds_resource.end;
+               p->leds_resource.name = "leds";
+
+               p->leds_pdev.name = "sunfire-fhc-leds";
+               p->leds_pdev.resource = &p->leds_resource;
+               p->leds_pdev.num_resources = 1;
+               p->leds_pdev.dev.parent = &op->dev;
+
+               err = platform_device_register(&p->leds_pdev);
+               if (err) {
+                       printk(KERN_ERR "fhc: Could not register LEDS "
+                              "platform device\n");
+                       goto out_unmap_pregs;
+               }
+       }
+       reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
 
-       tmp = upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
+       if (!p->central)
+               reg |= FHC_CONTROL_IXIST;
 
-       /* NOTE: reverse logic on this bit */
-       if (on)
-               tmp &= ~(FHC_CONTROL_RLED);
-       else
-               tmp |= FHC_CONTROL_RLED;
-       tmp &= ~(FHC_CONTROL_AOFF | FHC_CONTROL_BOFF | FHC_CONTROL_SLINE);
+       reg &= ~(FHC_CONTROL_AOFF |
+                FHC_CONTROL_BOFF |
+                FHC_CONTROL_SLINE);
 
-       upa_writel(tmp, fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-       upa_readl(fhc->fhc_regs.pregs + FHC_PREGS_CTRL);
-}
+       upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+       upa_readl(p->pregs + FHC_PREGS_CTRL);
 
-static inline void central_ledblink(struct linux_central *central, int on)
-{
-       u8 tmp;
-
-       tmp = upa_readb(central->clkregs + CLOCK_CTRL);
+       reg = upa_readl(p->pregs + FHC_PREGS_ID);
+       printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
+              p->board_num,
+              (reg & FHC_ID_VERS) >> 28,
+              (reg & FHC_ID_PARTID) >> 12,
+              (reg & FHC_ID_MANUF) >> 1,
+              (p->jtag_master ?
+               "(JTAG Master)" :
+               (p->central ? "(Central)" : "")));
 
-       /* NOTE: reverse logic on this bit */
-       if (on)
-               tmp &= ~(CLOCK_CTRL_RLED);
-       else
-               tmp |= CLOCK_CTRL_RLED;
+       err = 0;
 
-       upa_writeb(tmp, central->clkregs + CLOCK_CTRL);
-       upa_readb(central->clkregs + CLOCK_CTRL);
-}
+out:
+       return err;
 
-static struct timer_list sftimer;
-static int led_state;
+out_unmap_pregs:
+       of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
 
-static void sunfire_timer(unsigned long __ignored)
-{
-       struct linux_fhc *fhc;
-
-       central_ledblink(central_bus, led_state);
-       for (fhc = fhc_list; fhc != NULL; fhc = fhc->next)
-               if (! IS_CENTRAL_FHC(fhc))
-                       fhc_ledblink(fhc, led_state);
-       led_state = ! led_state;
-       sftimer.expires = jiffies + (HZ >> 1);
-       add_timer(&sftimer);
+out_free:
+       kfree(p);
+       goto out;
 }
 
-/* After PCI/SBUS busses have been probed, this is called to perform
- * final initialization of all FireHose Controllers in the system.
- */
-void firetruck_init(void)
+static struct of_device_id __initdata fhc_match[] = {
+       {
+               .name = "fhc",
+       },
+       {},
+};
+
+static struct of_platform_driver fhc_driver = {
+       .match_table    = fhc_match,
+       .probe          = fhc_probe,
+       .driver         = {
+               .name   = "fhc",
+       },
+};
+
+static int __init sunfire_init(void)
 {
-       struct linux_central *central = central_bus;
-       u8 ctrl;
-
-       /* No central bus, nothing to do. */
-       if (central == NULL)
-               return;
-
-       /* OBP leaves it on, turn it off so clock board timer LED
-        * is in sync with FHC ones.
-        */
-       ctrl = upa_readb(central->clkregs + CLOCK_CTRL);
-       ctrl &= ~(CLOCK_CTRL_RLED);
-       upa_writeb(ctrl, central->clkregs + CLOCK_CTRL);
-
-       led_state = 0;
-       init_timer(&sftimer);
-       sftimer.data = 0;
-       sftimer.function = &sunfire_timer;
-       sftimer.expires = jiffies + (HZ >> 1);
-       add_timer(&sftimer);
+       (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+       (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+       return 0;
 }
+
+subsys_initcall(sunfire_init);
index 6d4f02e8a4cfe7da672602b87ab49a8856ff7570..967b04886822273f73f00cf550007cb0c51da68b 100644 (file)
@@ -1,6 +1,6 @@
-/* memctrlr.c: Driver for UltraSPARC-III memory controller.
+/* chmc.c: Driver for UltraSPARC-III memory controller.
  *
- * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/spitfire.h>
 #include <asm/chmctrl.h>
 #include <asm/cpudata.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/head.h>
 #include <asm/io.h>
+#include <asm/memctrl.h>
+
+#define DRV_MODULE_NAME                "chmc"
+#define PFX DRV_MODULE_NAME    ": "
+#define DRV_MODULE_VERSION     "0.2"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int mc_type;
+#define MC_TYPE_SAFARI         1
+#define MC_TYPE_JBUS           2
+
+static dimm_printer_t us3mc_dimm_printer;
 
 #define CHMCTRL_NDGRPS 2
 #define CHMCTRL_NDIMMS 4
 
-#define DIMMS_PER_MC   (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+#define CHMC_DIMMS_PER_MC      (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
 
 /* OBP memory-layout property format. */
-struct obp_map {
+struct chmc_obp_map {
        unsigned char   dimm_map[144];
        unsigned char   pin_map[576];
 };
 
 #define DIMM_LABEL_SZ  8
 
-struct obp_mem_layout {
+struct chmc_obp_mem_layout {
        /* One max 8-byte string label per DIMM.  Usually
         * this matches the label on the motherboard where
         * that DIMM resides.
         */
-       char            dimm_labels[DIMMS_PER_MC][DIMM_LABEL_SZ];
+       char                    dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
 
        /* If symmetric use map[0], else it is
         * asymmetric and map[1] should be used.
         */
-       char            symmetric;
+       char                    symmetric;
 
-       struct obp_map  map[2];
+       struct chmc_obp_map     map[2];
 };
 
 #define CHMCTRL_NBANKS 4
 
-struct bank_info {
-       struct mctrl_info       *mp;
+struct chmc_bank_info {
+       struct chmc             *p;
        int                     bank_id;
 
        u64                     raw_reg;
@@ -65,28 +84,406 @@ struct bank_info {
        unsigned long           size;
 };
 
-struct mctrl_info {
-       struct list_head        list;
-       int                     portid;
+struct chmc {
+       struct list_head                list;
+       int                             portid;
+
+       struct chmc_obp_mem_layout      layout_prop;
+       int                             layout_size;
+
+       void __iomem                    *regs;
 
-       struct obp_mem_layout   layout_prop;
-       int                     layout_size;
+       u64                             timing_control1;
+       u64                             timing_control2;
+       u64                             timing_control3;
+       u64                             timing_control4;
+       u64                             memaddr_control;
 
-       void __iomem            *regs;
+       struct chmc_bank_info           logical_banks[CHMCTRL_NBANKS];
+};
+
+#define JBUSMC_REGS_SIZE               8
+
+#define JB_MC_REG1_DIMM2_BANK3         0x8000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK1         0x4000000000000000UL
+#define JB_MC_REG1_DIMM2_BANK2         0x2000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK0         0x1000000000000000UL
+#define JB_MC_REG1_XOR                 0x0000010000000000UL
+#define JB_MC_REG1_ADDR_GEN_2          0x000000e000000000UL
+#define JB_MC_REG1_ADDR_GEN_2_SHIFT    37
+#define JB_MC_REG1_ADDR_GEN_1          0x0000001c00000000UL
+#define JB_MC_REG1_ADDR_GEN_1_SHIFT    34
+#define JB_MC_REG1_INTERLEAVE          0x0000000001800000UL
+#define JB_MC_REG1_INTERLEAVE_SHIFT    23
+#define JB_MC_REG1_DIMM2_PTYPE         0x0000000000200000UL
+#define JB_MC_REG1_DIMM2_PTYPE_SHIFT   21
+#define JB_MC_REG1_DIMM1_PTYPE         0x0000000000100000UL
+#define JB_MC_REG1_DIMM1_PTYPE_SHIFT   20
+
+#define PART_TYPE_X8           0
+#define PART_TYPE_X4           1
+
+#define INTERLEAVE_NONE                0
+#define INTERLEAVE_SAME                1
+#define INTERLEAVE_INTERNAL    2
+#define INTERLEAVE_BOTH                3
+
+#define ADDR_GEN_128MB         0
+#define ADDR_GEN_256MB         1
+#define ADDR_GEN_512MB         2
+#define ADDR_GEN_1GB           3
+
+#define JB_NUM_DIMM_GROUPS     2
+#define JB_NUM_DIMMS_PER_GROUP 2
+#define JB_NUM_DIMMS           (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
+
+struct jbusmc_obp_map {
+       unsigned char   dimm_map[18];
+       unsigned char   pin_map[144];
+};
+
+struct jbusmc_obp_mem_layout {
+       /* One max 8-byte string label per DIMM.  Usually
+        * this matches the label on the motherboard where
+        * that DIMM resides.
+        */
+       char            dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ];
+
+       /* If symmetric use map[0], else it is
+        * asymmetric and map[1] should be used.
+        */
+       char                    symmetric;
+
+       struct jbusmc_obp_map   map;
+
+       char                    _pad;
+};
 
-       u64                     timing_control1;
-       u64                     timing_control2;
-       u64                     timing_control3;
-       u64                     timing_control4;
-       u64                     memaddr_control;
+struct jbusmc_dimm_group {
+       struct jbusmc                   *controller;
+       int                             index;
+       u64                             base_addr;
+       u64                             size;
+};
 
-       struct bank_info        logical_banks[CHMCTRL_NBANKS];
+struct jbusmc {
+       void __iomem                    *regs;
+       u64                             mc_reg_1;
+       u32                             portid;
+       struct jbusmc_obp_mem_layout    layout;
+       int                             layout_len;
+       int                             num_dimm_groups;
+       struct jbusmc_dimm_group        dimm_groups[JB_NUM_DIMM_GROUPS];
+       struct list_head                list;
 };
 
+static DEFINE_SPINLOCK(mctrl_list_lock);
 static LIST_HEAD(mctrl_list);
 
+static void mc_list_add(struct list_head *list)
+{
+       spin_lock(&mctrl_list_lock);
+       list_add(list, &mctrl_list);
+       spin_unlock(&mctrl_list_lock);
+}
+
+static void mc_list_del(struct list_head *list)
+{
+       spin_lock(&mctrl_list_lock);
+       list_del_init(list);
+       spin_unlock(&mctrl_list_lock);
+}
+
+#define SYNDROME_MIN   -1
+#define SYNDROME_MAX   144
+
+/* Covert syndrome code into the way the bits are positioned
+ * on the bus.
+ */
+static int syndrome_to_qword_code(int syndrome_code)
+{
+       if (syndrome_code < 128)
+               syndrome_code += 16;
+       else if (syndrome_code < 128 + 9)
+               syndrome_code -= (128 - 7);
+       else if (syndrome_code < (128 + 9 + 3))
+               syndrome_code -= (128 + 9 - 4);
+       else
+               syndrome_code -= (128 + 9 + 3);
+       return syndrome_code;
+}
+
+/* All this magic has to do with how a cache line comes over the wire
+ * on Safari and JBUS.  A 64-bit line comes over in 1 or more quadword
+ * cycles, each of which transmit ECC/MTAG info as well as the actual
+ * data.
+ */
+#define L2_LINE_SIZE           64
+#define L2_LINE_ADDR_MSK       (L2_LINE_SIZE - 1)
+#define QW_PER_LINE            4
+#define QW_BYTES               (L2_LINE_SIZE / QW_PER_LINE)
+#define QW_BITS                        144
+#define SAFARI_LAST_BIT                (576 - 1)
+#define JBUS_LAST_BIT          (144 - 1)
+
+static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr,
+                                int *pin_p, char **dimm_str_p, void *_prop,
+                                int base_dimm_offset)
+{
+       int qword_code = syndrome_to_qword_code(syndrome_code);
+       int cache_line_offset;
+       int offset_inverse;
+       int dimm_map_index;
+       int map_val;
+
+       if (mc_type == MC_TYPE_JBUS) {
+               struct jbusmc_obp_mem_layout *p = _prop;
+
+               /* JBUS */
+               cache_line_offset = qword_code;
+               offset_inverse = (JBUS_LAST_BIT - cache_line_offset);
+               dimm_map_index = offset_inverse / 8;
+               map_val = p->map.dimm_map[dimm_map_index];
+               map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1);
+               *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+               *pin_p = p->map.pin_map[cache_line_offset];
+       } else {
+               struct chmc_obp_mem_layout *p = _prop;
+               struct chmc_obp_map *mp;
+               int qword;
+
+               /* Safari */
+               if (p->symmetric)
+                       mp = &p->map[0];
+               else
+                       mp = &p->map[1];
+
+               qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES;
+               cache_line_offset = ((3 - qword) * QW_BITS) + qword_code;
+               offset_inverse = (SAFARI_LAST_BIT - cache_line_offset);
+               dimm_map_index = offset_inverse >> 2;
+               map_val = mp->dimm_map[dimm_map_index];
+               map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3);
+               *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+               *pin_p = mp->pin_map[cache_line_offset];
+       }
+}
+
+static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr)
+{
+       struct jbusmc *p;
+
+       list_for_each_entry(p, &mctrl_list, list) {
+               int i;
+
+               for (i = 0; i < p->num_dimm_groups; i++) {
+                       struct jbusmc_dimm_group *dp = &p->dimm_groups[i];
+
+                       if (phys_addr < dp->base_addr ||
+                           (dp->base_addr + dp->size) <= phys_addr)
+                               continue;
+
+                       return dp;
+               }
+       }
+       return NULL;
+}
+
+static int jbusmc_print_dimm(int syndrome_code,
+                            unsigned long phys_addr,
+                            char *buf, int buflen)
+{
+       struct jbusmc_obp_mem_layout *prop;
+       struct jbusmc_dimm_group *dp;
+       struct jbusmc *p;
+       int first_dimm;
+
+       dp = jbusmc_find_dimm_group(phys_addr);
+       if (dp == NULL ||
+           syndrome_code < SYNDROME_MIN ||
+           syndrome_code > SYNDROME_MAX) {
+               buf[0] = '?';
+               buf[1] = '?';
+               buf[2] = '?';
+               buf[3] = '\0';
+       }
+       p = dp->controller;
+       prop = &p->layout;
+
+       first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP;
+
+       if (syndrome_code != SYNDROME_MIN) {
+               char *dimm_str;
+               int pin;
+
+               get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+                                    &dimm_str, prop, first_dimm);
+               sprintf(buf, "%s, pin %3d", dimm_str, pin);
+       } else {
+               int dimm;
+
+               /* Multi-bit error, we just dump out all the
+                * dimm labels associated with this dimm group.
+                */
+               for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) {
+                       sprintf(buf, "%s ",
+                               prop->dimm_labels[first_dimm + dimm]);
+                       buf += strlen(buf);
+               }
+       }
+
+       return 0;
+}
+
+static u64 __devinit jbusmc_dimm_group_size(u64 base,
+                                           const struct linux_prom64_registers *mem_regs,
+                                           int num_mem_regs)
+{
+       u64 max = base + (8UL * 1024 * 1024 * 1024);
+       u64 max_seen = base;
+       int i;
+
+       for (i = 0; i < num_mem_regs; i++) {
+               const struct linux_prom64_registers *ent;
+               u64 this_base;
+               u64 this_end;
+
+               ent = &mem_regs[i];
+               this_base = ent->phys_addr;
+               this_end = this_base + ent->reg_size;
+               if (base < this_base || base >= this_end)
+                       continue;
+               if (this_end > max)
+                       this_end = max;
+               if (this_end > max_seen)
+                       max_seen = this_end;
+       }
+
+       return max_seen - base;
+}
+
+static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
+                                                     unsigned long index,
+                                                     const struct linux_prom64_registers *mem_regs,
+                                                     int num_mem_regs)
+{
+       struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
+
+       dp->controller = p;
+       dp->index = index;
+
+       dp->base_addr  = (p->portid * (64UL * 1024 * 1024 * 1024));
+       dp->base_addr += (index * (8UL * 1024 * 1024 * 1024));
+       dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
+}
+
+static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
+                                                  const struct linux_prom64_registers *mem_regs,
+                                                  int num_mem_regs)
+{
+       if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
+               jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
+               p->num_dimm_groups++;
+       }
+       if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) {
+               jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs);
+               p->num_dimm_groups++;
+       }
+}
+
+static int __devinit jbusmc_probe(struct of_device *op,
+                                 const struct of_device_id *match)
+{
+       const struct linux_prom64_registers *mem_regs;
+       struct device_node *mem_node;
+       int err, len, num_mem_regs;
+       struct jbusmc *p;
+       const u32 *prop;
+       const void *ml;
+
+       err = -ENODEV;
+       mem_node = of_find_node_by_path("/memory");
+       if (!mem_node) {
+               printk(KERN_ERR PFX "Cannot find /memory node.\n");
+               goto out;
+       }
+       mem_regs = of_get_property(mem_node, "reg", &len);
+       if (!mem_regs) {
+               printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n");
+               goto out;
+       }
+       num_mem_regs = len / sizeof(*mem_regs);
+
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n");
+               goto out;
+       }
+
+       INIT_LIST_HEAD(&p->list);
+
+       err = -ENODEV;
+       prop = of_get_property(op->node, "portid", &len);
+       if (!prop || len != 4) {
+               printk(KERN_ERR PFX "Cannot find portid.\n");
+               goto out_free;
+       }
+
+       p->portid = *prop;
+
+       prop = of_get_property(op->node, "memory-control-register-1", &len);
+       if (!prop || len != 8) {
+               printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
+               goto out_free;
+       }
+
+       p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1];
+
+       err = -ENOMEM;
+       p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map jbusmc regs.\n");
+               goto out_free;
+       }
+
+       err = -ENODEV;
+       ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+       if (!ml) {
+               printk(KERN_ERR PFX "Cannot get memory layout property.\n");
+               goto out_iounmap;
+       }
+       if (p->layout_len > sizeof(p->layout)) {
+               printk(KERN_ERR PFX "Unexpected memory-layout size %d\n",
+                      p->layout_len);
+               goto out_iounmap;
+       }
+       memcpy(&p->layout, ml, p->layout_len);
+
+       jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs);
+
+       mc_list_add(&p->list);
+
+       printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
+              op->node->full_name);
+
+       dev_set_drvdata(&op->dev, p);
+
+       err = 0;
+
+out:
+       return err;
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
 /* Does BANK decode PHYS_ADDR? */
-static int bank_match(struct bank_info *bp, unsigned long phys_addr)
+static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
 {
        unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
        unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
@@ -118,25 +515,18 @@ static int bank_match(struct bank_info *bp, unsigned long phys_addr)
 }
 
 /* Given PHYS_ADDR, search memory controller banks for a match. */
-static struct bank_info *find_bank(unsigned long phys_addr)
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
 {
-       struct list_head *mctrl_head = &mctrl_list;
-       struct list_head *mctrl_entry = mctrl_head->next;
+       struct chmc *p;
 
-       for (;;) {
-               struct mctrl_info *mp =
-                       list_entry(mctrl_entry, struct mctrl_info, list);
+       list_for_each_entry(p, &mctrl_list, list) {
                int bank_no;
 
-               if (mctrl_entry == mctrl_head)
-                       break;
-               mctrl_entry = mctrl_entry->next;
-
                for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
-                       struct bank_info *bp;
+                       struct chmc_bank_info *bp;
 
-                       bp = &mp->logical_banks[bank_no];
-                       if (bank_match(bp, phys_addr))
+                       bp = &p->logical_banks[bank_no];
+                       if (chmc_bank_match(bp, phys_addr))
                                return bp;
                }
        }
@@ -145,17 +535,15 @@ static struct bank_info *find_bank(unsigned long phys_addr)
 }
 
 /* This is the main purpose of this driver. */
-#define SYNDROME_MIN   -1
-#define SYNDROME_MAX   144
-int chmc_getunumber(int syndrome_code,
-                   unsigned long phys_addr,
-                   char *buf, int buflen)
+static int chmc_print_dimm(int syndrome_code,
+                          unsigned long phys_addr,
+                          char *buf, int buflen)
 {
-       struct bank_info *bp;
-       struct obp_mem_layout *prop;
+       struct chmc_bank_info *bp;
+       struct chmc_obp_mem_layout *prop;
        int bank_in_controller, first_dimm;
 
-       bp = find_bank(phys_addr);
+       bp = chmc_find_bank(phys_addr);
        if (bp == NULL ||
            syndrome_code < SYNDROME_MIN ||
            syndrome_code > SYNDROME_MAX) {
@@ -166,60 +554,18 @@ int chmc_getunumber(int syndrome_code,
                return 0;
        }
 
-       prop = &bp->mp->layout_prop;
+       prop = &bp->p->layout_prop;
        bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
        first_dimm  = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
        first_dimm *= CHMCTRL_NDIMMS;
 
        if (syndrome_code != SYNDROME_MIN) {
-               struct obp_map *map;
-               int qword, where_in_line, where, map_index, map_offset;
-               unsigned int map_val;
+               char *dimm_str;
+               int pin;
 
-               /* Yaay, single bit error so we can figure out
-                * the exact dimm.
-                */
-               if (prop->symmetric)
-                       map = &prop->map[0];
-               else
-                       map = &prop->map[1];
-
-               /* Covert syndrome code into the way the bits are
-                * positioned on the bus.
-                */
-               if (syndrome_code < 144 - 16)
-                       syndrome_code += 16;
-               else if (syndrome_code < 144)
-                       syndrome_code -= (144 - 7);
-               else if (syndrome_code < (144 + 3))
-                       syndrome_code -= (144 + 3 - 4);
-               else
-                       syndrome_code -= 144 + 3;
-
-               /* All this magic has to do with how a cache line
-                * comes over the wire on Safari.  A 64-bit line
-                * comes over in 4 quadword cycles, each of which
-                * transmit ECC/MTAG info as well as the actual
-                * data.  144 bits per quadword, 576 total.
-                */
-#define LINE_SIZE      64
-#define LINE_ADDR_MSK  (LINE_SIZE - 1)
-#define QW_PER_LINE    4
-#define QW_BYTES       (LINE_SIZE / QW_PER_LINE)
-#define QW_BITS                144
-#define LAST_BIT       (576 - 1)
-
-               qword = (phys_addr & LINE_ADDR_MSK) / QW_BYTES;
-               where_in_line = ((3 - qword) * QW_BITS) + syndrome_code;
-               where = (LAST_BIT - where_in_line);
-               map_index = where >> 2;
-               map_offset = where & 0x3;
-               map_val = map->dimm_map[map_index];
-               map_val = ((map_val >> ((3 - map_offset) << 1)) & (2 - 1));
-
-               sprintf(buf, "%s, pin %3d",
-                       prop->dimm_labels[first_dimm + map_val],
-                       map->pin_map[where_in_line]);
+               get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+                                    &dimm_str, prop, first_dimm);
+               sprintf(buf, "%s, pin %3d", dimm_str, pin);
        } else {
                int dimm;
 
@@ -240,7 +586,7 @@ int chmc_getunumber(int syndrome_code,
  * the code is executing, you must use special ASI load/store else
  * you go through the global mapping.
  */
-static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
 {
        unsigned long ret, this_cpu;
 
@@ -248,14 +594,14 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
 
        this_cpu = real_hard_smp_processor_id();
 
-       if (mp->portid == this_cpu) {
+       if (p->portid == this_cpu) {
                __asm__ __volatile__("ldxa      [%1] %2, %0"
                                     : "=r" (ret)
                                     : "r" (offset), "i" (ASI_MCU_CTRL_REG));
        } else {
                __asm__ __volatile__("ldxa      [%1] %2, %0"
                                     : "=r" (ret)
-                                    : "r" (mp->regs + offset),
+                                    : "r" (p->regs + offset),
                                       "i" (ASI_PHYS_BYPASS_EC_E));
        }
 
@@ -265,178 +611,253 @@ static u64 read_mcreg(struct mctrl_info *mp, unsigned long offset)
 }
 
 #if 0 /* currently unused */
-static void write_mcreg(struct mctrl_info *mp, unsigned long offset, u64 val)
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
 {
-       if (mp->portid == smp_processor_id()) {
+       if (p->portid == smp_processor_id()) {
                __asm__ __volatile__("stxa      %0, [%1] %2"
                                     : : "r" (val),
                                         "r" (offset), "i" (ASI_MCU_CTRL_REG));
        } else {
                __asm__ __volatile__("ldxa      %0, [%1] %2"
                                     : : "r" (val),
-                                        "r" (mp->regs + offset),
+                                        "r" (p->regs + offset),
                                         "i" (ASI_PHYS_BYPASS_EC_E));
        }
 }
 #endif
 
-static void interpret_one_decode_reg(struct mctrl_info *mp, int which_bank, u64 val)
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
 {
-       struct bank_info *p = &mp->logical_banks[which_bank];
-
-       p->mp = mp;
-       p->bank_id = (CHMCTRL_NBANKS * mp->portid) + which_bank;
-       p->raw_reg = val;
-       p->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
-       p->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
-       p->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
-       p->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
-       p->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
-
-       p->base  =  (p->um);
-       p->base &= ~(p->uk);
-       p->base <<= PA_UPPER_BITS_SHIFT;
-
-       switch(p->lk) {
+       struct chmc_bank_info *bp = &p->logical_banks[which_bank];
+
+       bp->p = p;
+       bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
+       bp->raw_reg = val;
+       bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+       bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+       bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+       bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+       bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+
+       bp->base  =  (bp->um);
+       bp->base &= ~(bp->uk);
+       bp->base <<= PA_UPPER_BITS_SHIFT;
+
+       switch(bp->lk) {
        case 0xf:
        default:
-               p->interleave = 1;
+               bp->interleave = 1;
                break;
 
        case 0xe:
-               p->interleave = 2;
+               bp->interleave = 2;
                break;
 
        case 0xc:
-               p->interleave = 4;
+               bp->interleave = 4;
                break;
 
        case 0x8:
-               p->interleave = 8;
+               bp->interleave = 8;
                break;
 
        case 0x0:
-               p->interleave = 16;
+               bp->interleave = 16;
                break;
        };
 
        /* UK[10] is reserved, and UK[11] is not set for the SDRAM
         * bank size definition.
         */
-       p->size = (((unsigned long)p->uk &
-                   ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
-       p->size /= p->interleave;
+       bp->size = (((unsigned long)bp->uk &
+                    ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+       bp->size /= bp->interleave;
 }
 
-static void fetch_decode_regs(struct mctrl_info *mp)
+static void chmc_fetch_decode_regs(struct chmc *p)
 {
-       if (mp->layout_size == 0)
+       if (p->layout_size == 0)
                return;
 
-       interpret_one_decode_reg(mp, 0,
-                                read_mcreg(mp, CHMCTRL_DECODE1));
-       interpret_one_decode_reg(mp, 1,
-                                read_mcreg(mp, CHMCTRL_DECODE2));
-       interpret_one_decode_reg(mp, 2,
-                                read_mcreg(mp, CHMCTRL_DECODE3));
-       interpret_one_decode_reg(mp, 3,
-                                read_mcreg(mp, CHMCTRL_DECODE4));
+       chmc_interpret_one_decode_reg(p, 0,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE1));
+       chmc_interpret_one_decode_reg(p, 1,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE2));
+       chmc_interpret_one_decode_reg(p, 2,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE3));
+       chmc_interpret_one_decode_reg(p, 3,
+                                     chmc_read_mcreg(p, CHMCTRL_DECODE4));
 }
 
-static int init_one_mctrl(struct device_node *dp)
+static int __devinit chmc_probe(struct of_device *op,
+                               const struct of_device_id *match)
 {
-       struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL);
-       int portid = of_getintprop_default(dp, "portid", -1);
-       const struct linux_prom64_registers *regs;
+       struct device_node *dp = op->node;
+       unsigned long ver;
        const void *pval;
-       int len;
+       int len, portid;
+       struct chmc *p;
+       int err;
+
+       err = -ENODEV;
+       __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+       if ((ver >> 32UL) == __JALAPENO_ID ||
+           (ver >> 32UL) == __SERRANO_ID)
+               goto out;
 
-       if (!mp)
-               return -1;
+       portid = of_getintprop_default(dp, "portid", -1);
        if (portid == -1)
-               goto fail;
+               goto out;
 
-       mp->portid = portid;
        pval = of_get_property(dp, "memory-layout", &len);
-       mp->layout_size = len;
-       if (!pval)
-               mp->layout_size = 0;
-       else {
-               if (mp->layout_size > sizeof(mp->layout_prop))
-                       goto fail;
-               memcpy(&mp->layout_prop, pval, len);
+       if (pval && len > sizeof(p->layout_prop)) {
+               printk(KERN_ERR PFX "Unexpected memory-layout property "
+                      "size %d.\n", len);
+               goto out;
        }
 
-       regs = of_get_property(dp, "reg", NULL);
-       if (!regs || regs->reg_size != 0x48)
-               goto fail;
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+               goto out;
+       }
 
-       mp->regs = ioremap(regs->phys_addr, regs->reg_size);
-       if (mp->regs == NULL)
-               goto fail;
+       p->portid = portid;
+       p->layout_size = len;
+       if (!pval)
+               p->layout_size = 0;
+       else
+               memcpy(&p->layout_prop, pval, len);
+
+       p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Could not map registers.\n");
+               goto out_free;
+       }
 
-       if (mp->layout_size != 0UL) {
-               mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1);
-               mp->timing_control2 = read_mcreg(mp, CHMCTRL_TCTRL2);
-               mp->timing_control3 = read_mcreg(mp, CHMCTRL_TCTRL3);
-               mp->timing_control4 = read_mcreg(mp, CHMCTRL_TCTRL4);
-               mp->memaddr_control = read_mcreg(mp, CHMCTRL_MACTRL);
+       if (p->layout_size != 0UL) {
+               p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
+               p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
+               p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
+               p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
+               p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
        }
 
-       fetch_decode_regs(mp);
+       chmc_fetch_decode_regs(p);
 
-       list_add(&mp->list, &mctrl_list);
+       mc_list_add(&p->list);
 
-       /* Report the device. */
-       printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n",
+       printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
               dp->full_name,
-              mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE"));
+              (p->layout_size ? "ACTIVE" : "INACTIVE"));
 
-       return 0;
+       dev_set_drvdata(&op->dev, p);
+
+       err = 0;
+
+out:
+       return err;
+
+out_free:
+       kfree(p);
+       goto out;
+}
 
-fail:
-       if (mp) {
-               if (mp->regs != NULL)
-                       iounmap(mp->regs);
-               kfree(mp);
+static int __devinit us3mc_probe(struct of_device *op,
+                               const struct of_device_id *match)
+{
+       if (mc_type == MC_TYPE_SAFARI)
+               return chmc_probe(op, match);
+       else if (mc_type == MC_TYPE_JBUS)
+               return jbusmc_probe(op, match);
+       return -ENODEV;
+}
+
+static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+{
+       list_del(&p->list);
+       of_iounmap(&op->resource[0], p->regs, 0x48);
+       kfree(p);
+}
+
+static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+{
+       mc_list_del(&p->list);
+       of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+       kfree(p);
+}
+
+static int __devexit us3mc_remove(struct of_device *op)
+{
+       void *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               if (mc_type == MC_TYPE_SAFARI)
+                       chmc_destroy(op, p);
+               else if (mc_type == MC_TYPE_JBUS)
+                       jbusmc_destroy(op, p);
        }
-       return -1;
+       return 0;
+}
+
+static const struct of_device_id us3mc_match[] = {
+       {
+               .name = "memory-controller",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, us3mc_match);
+
+static struct of_platform_driver us3mc_driver = {
+       .name           = "us3mc",
+       .match_table    = us3mc_match,
+       .probe          = us3mc_probe,
+       .remove         = __devexit_p(us3mc_remove),
+};
+
+static inline bool us3mc_platform(void)
+{
+       if (tlb_type == cheetah || tlb_type == cheetah_plus)
+               return true;
+       return false;
 }
 
-static int __init chmc_init(void)
+static int __init us3mc_init(void)
 {
-       struct device_node *dp;
+       unsigned long ver;
+       int ret;
 
-       /* This driver is only for cheetah platforms. */
-       if (tlb_type != cheetah && tlb_type != cheetah_plus)
+       if (!us3mc_platform())
                return -ENODEV;
 
-       for_each_node_by_name(dp, "memory-controller")
-               init_one_mctrl(dp);
+       __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+       if ((ver >> 32UL) == __JALAPENO_ID ||
+           (ver >> 32UL) == __SERRANO_ID) {
+               mc_type = MC_TYPE_JBUS;
+               us3mc_dimm_printer = jbusmc_print_dimm;
+       } else {
+               mc_type = MC_TYPE_SAFARI;
+               us3mc_dimm_printer = chmc_print_dimm;
+       }
 
-       for_each_node_by_name(dp, "mc-us3")
-               init_one_mctrl(dp);
+       ret = register_dimm_printer(us3mc_dimm_printer);
 
-       return 0;
+       if (!ret) {
+               ret = of_register_driver(&us3mc_driver, &of_bus_type);
+               if (ret)
+                       unregister_dimm_printer(us3mc_dimm_printer);
+       }
+       return ret;
 }
 
-static void __exit chmc_cleanup(void)
+static void __exit us3mc_cleanup(void)
 {
-       struct list_head *head = &mctrl_list;
-       struct list_head *tmp = head->next;
-
-       for (;;) {
-               struct mctrl_info *p =
-                       list_entry(tmp, struct mctrl_info, list);
-               if (tmp == head)
-                       break;
-               tmp = tmp->next;
-
-               list_del(&p->list);
-               iounmap(p->regs);
-               kfree(p);
+       if (us3mc_platform()) {
+               unregister_dimm_printer(us3mc_dimm_printer);
+               of_unregister_driver(&us3mc_driver);
        }
 }
 
-module_init(chmc_init);
-module_exit(chmc_cleanup);
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
index 0097c08dc600e2f432d6a8da965962ab9b3b2bcd..0c9ac83ed0a89949c562d962f30c3837c04958b6 100644 (file)
@@ -1,7 +1,7 @@
 /* cpu.c: Dinky routines to look for the kind of Sparc cpu
  *        we are on.
  *
- * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 
 DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
 
-struct cpu_iu_info {
-  short manuf;
-  short impl;
-  char* cpu_name;   /* should be enough I hope... */
+struct cpu_chip_info {
+       unsigned short  manuf;
+       unsigned short  impl;
+       const char      *cpu_name;
+       const char      *fp_name;
 };
 
-struct cpu_fp_info {
-  short manuf;
-  short impl;
-  char fpu_vers;
-  char* fp_name;
+static const struct cpu_chip_info cpu_chips[] = {
+       {
+               .manuf          = 0x17,
+               .impl           = 0x10,
+               .cpu_name       = "TI UltraSparc I   (SpitFire)",
+               .fp_name        = "UltraSparc I integrated FPU",
+       },
+       {
+               .manuf          = 0x22,
+               .impl           = 0x10,
+               .cpu_name       = "TI UltraSparc I   (SpitFire)",
+               .fp_name        = "UltraSparc I integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x11,
+               .cpu_name       = "TI UltraSparc II  (BlackBird)",
+               .fp_name        = "UltraSparc II integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x12,
+               .cpu_name       = "TI UltraSparc IIi (Sabre)",
+               .fp_name        = "UltraSparc IIi integrated FPU",
+       },
+       {
+               .manuf          = 0x17,
+               .impl           = 0x13,
+               .cpu_name       = "TI UltraSparc IIe (Hummingbird)",
+               .fp_name        = "UltraSparc IIe integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x14,
+               .cpu_name       = "TI UltraSparc III (Cheetah)",
+               .fp_name        = "UltraSparc III integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x15,
+               .cpu_name       = "TI UltraSparc III+ (Cheetah+)",
+               .fp_name        = "UltraSparc III+ integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x16,
+               .cpu_name       = "TI UltraSparc IIIi (Jalapeno)",
+               .fp_name        = "UltraSparc IIIi integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x18,
+               .cpu_name       = "TI UltraSparc IV (Jaguar)",
+               .fp_name        = "UltraSparc IV integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x19,
+               .cpu_name       = "TI UltraSparc IV+ (Panther)",
+               .fp_name        = "UltraSparc IV+ integrated FPU",
+       },
+       {
+               .manuf          = 0x3e,
+               .impl           = 0x22,
+               .cpu_name       = "TI UltraSparc IIIi+ (Serrano)",
+               .fp_name        = "UltraSparc IIIi+ integrated FPU",
+       },
 };
 
-static struct cpu_fp_info linux_sparc_fpu[] = {
-  { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
-  { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
-  { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
-  { 0x3e, 0x14, 0, "UltraSparc III integrated FPU"},
-  { 0x3e, 0x15, 0, "UltraSparc III+ integrated FPU"},
-  { 0x3e, 0x16, 0, "UltraSparc IIIi integrated FPU"},
-  { 0x3e, 0x18, 0, "UltraSparc IV integrated FPU"},
-  { 0x3e, 0x19, 0, "UltraSparc IV+ integrated FPU"},
-  { 0x3e, 0x22, 0, "UltraSparc IIIi+ integrated FPU"},
-};
-
-#define NSPARCFPU  ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
-  { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
-  { 0x17, 0x12, "TI UltraSparc IIi (Sabre)"},
-  { 0x17, 0x13, "TI UltraSparc IIe (Hummingbird)"},
-  { 0x3e, 0x14, "TI UltraSparc III (Cheetah)"},
-  { 0x3e, 0x15, "TI UltraSparc III+ (Cheetah+)"},
-  { 0x3e, 0x16, "TI UltraSparc IIIi (Jalapeno)"},
-  { 0x3e, 0x18, "TI UltraSparc IV (Jaguar)"},
-  { 0x3e, 0x19, "TI UltraSparc IV+ (Panther)"},
-  { 0x3e, 0x22, "TI UltraSparc IIIi+ (Serrano)"},
-};
+#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
 
-#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
-
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
 
 static void __init sun4v_cpu_probe(void)
 {
@@ -89,68 +122,45 @@ static void __init sun4v_cpu_probe(void)
        }
 }
 
-void __init cpu_probe(void)
+static const struct cpu_chip_info * __init find_cpu_chip(unsigned short manuf,
+                                                        unsigned short impl)
 {
-       unsigned long ver, fpu_vers, manuf, impl, fprs;
        int i;
-       
-       if (tlb_type == hypervisor) {
-               sun4v_cpu_probe();
-               return;
-       }
 
-       fprs = fprs_read();
-       fprs_write(FPRS_FEF);
-       __asm__ __volatile__ ("rdpr %%ver, %0; stx %%fsr, [%1]"
-                             : "=&r" (ver)
-                             : "r" (&fpu_vers));
-       fprs_write(fprs);
-       
-       manuf = ((ver >> 48) & 0xffff);
-       impl = ((ver >> 32) & 0xffff);
-
-       fpu_vers = ((fpu_vers >> 17) & 0x7);
-
-retry:
-       for (i = 0; i < NSPARCCHIPS; i++) {
-               if (linux_sparc_chips[i].manuf == manuf) {
-                       if (linux_sparc_chips[i].impl == impl) {
-                               sparc_cpu_type =
-                                       linux_sparc_chips[i].cpu_name;
-                               break;
-                       }
-               }
-       }
+       for (i = 0; i < ARRAY_SIZE(cpu_chips); i++) {
+               const struct cpu_chip_info *p = &cpu_chips[i];
 
-       if (i == NSPARCCHIPS) {
-               /* Maybe it is a cheetah+ derivative, report it as cheetah+
-                * in that case until we learn the real names.
-                */
-               if (manuf == 0x3e &&
-                   impl > 0x15) {
-                       impl = 0x15;
-                       goto retry;
-               } else {
-                       printk("DEBUG: manuf[%lx] impl[%lx]\n",
-                              manuf, impl);
-               }
-               sparc_cpu_type = "Unknown CPU";
+               if (p->manuf == manuf && p->impl == impl)
+                       return p;
        }
+       return NULL;
+}
 
-       for (i = 0; i < NSPARCFPU; i++) {
-               if (linux_sparc_fpu[i].manuf == manuf &&
-                   linux_sparc_fpu[i].impl == impl) {
-                       if (linux_sparc_fpu[i].fpu_vers == fpu_vers) {
-                               sparc_fpu_type =
-                                       linux_sparc_fpu[i].fp_name;
-                               break;
-                       }
+static int __init cpu_type_probe(void)
+{
+       if (tlb_type == hypervisor) {
+               sun4v_cpu_probe();
+       } else {
+               unsigned long ver, manuf, impl;
+               const struct cpu_chip_info *p;
+       
+               __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+       
+               manuf = ((ver >> 48) & 0xffff);
+               impl = ((ver >> 32) & 0xffff);
+
+               p = find_cpu_chip(manuf, impl);
+               if (p) {
+                       sparc_cpu_type = p->cpu_name;
+                       sparc_fpu_type = p->fp_name;
+               } else {
+                       printk(KERN_ERR "CPU: Unknown chip, manuf[%lx] impl[%lx]\n",
+                              manuf, impl);
+                       sparc_cpu_type = "Unknown CPU";
+                       sparc_fpu_type = "Unknown FPU";
                }
        }
-
-       if (i == NSPARCFPU) {
-               printk("DEBUG: manuf[%lx] impl[%lx] fsr.vers[%lx]\n",
-                      manuf, impl, fpu_vers);
-               sparc_fpu_type = "Unknown FPU";
-       }
+       return 0;
 }
+
+arch_initcall(cpu_type_probe);
index d0fa5aa389341cf3020b40180f86c696b22600fd..f52e0534d91d060c58445e483928c66099517cc7 100644 (file)
@@ -1,6 +1,6 @@
 /* ds.c: Domain Services driver for Logical Domains
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
@@ -1217,7 +1217,7 @@ static int ds_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id ds_match[] = {
+static struct vio_device_id __initdata ds_match[] = {
        {
                .type = "domain-services-port",
        },
index 60d36d1425595583ddf9908afadfb3f242bb403e..77dbf6d45fafc175e6b602f316cb7ace8a2bb52f 100644 (file)
@@ -1,5 +1,4 @@
-/*
- * ebus.c: PCI to EBus bridge device.
+/* ebus.c: EBUS DMA library code.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 1999  David S. Miller (davem@redhat.com)
@@ -9,23 +8,11 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/string.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-#include <asm/io.h>
 
-/* EBUS dma library. */
+#include <asm/ebus_dma.h>
+#include <asm/io.h>
 
 #define EBDMA_CSR      0x00UL  /* Control/Status */
 #define EBDMA_ADDR     0x04UL  /* DMA Address */
@@ -268,283 +255,3 @@ void ebus_dma_enable(struct ebus_dma_info *p, int on)
        spin_unlock_irqrestore(&p->lock, flags);
 }
 EXPORT_SYMBOL(ebus_dma_enable);
-
-struct linux_ebus *ebus_chain = NULL;
-
-static inline void *ebus_alloc(size_t size)
-{
-       void *mem;
-
-       mem = kzalloc(size, GFP_ATOMIC);
-       if (!mem)
-               panic("ebus_alloc: out of memory");
-       return mem;
-}
-
-static void __init fill_ebus_child(struct device_node *dp,
-                                  struct linux_ebus_child *dev,
-                                  int non_standard_regs)
-{
-       struct of_device *op;
-       const int *regs;
-       int i, len;
-
-       dev->prom_node = dp;
-       printk(" (%s)", dp->name);
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs)
-               dev->num_addrs = 0;
-       else
-               dev->num_addrs = len / sizeof(regs[0]);
-
-       if (non_standard_regs) {
-               /* This is to handle reg properties which are not
-                * in the parent relative format.  One example are
-                * children of the i2c device on CompactPCI systems.
-                *
-                * So, for such devices we just record the property
-                * raw in the child resources.
-                */
-               for (i = 0; i < dev->num_addrs; i++)
-                       dev->resource[i].start = regs[i];
-       } else {
-               for (i = 0; i < dev->num_addrs; i++) {
-                       int rnum = regs[i];
-                       if (rnum >= dev->parent->num_addrs) {
-                               prom_printf("UGH: property for %s was %d, need < %d\n",
-                                           dp->name, len, dev->parent->num_addrs);
-                               prom_halt();
-                       }
-                       dev->resource[i].start = dev->parent->resource[i].start;
-                       dev->resource[i].end = dev->parent->resource[i].end;
-                       dev->resource[i].flags = IORESOURCE_MEM;
-                       dev->resource[i].name = dp->name;
-               }
-       }
-
-       op = of_find_device_by_node(dp);
-       if (!op) {
-               dev->num_irqs = 0;
-       } else {
-               dev->num_irqs = op->num_irqs;
-               for (i = 0; i < dev->num_irqs; i++)
-                       dev->irqs[i] = op->irqs[i];
-       }
-
-       if (!dev->num_irqs) {
-               /*
-                * Oh, well, some PROMs don't export interrupts
-                * property to children of EBus devices...
-                *
-                * Be smart about PS/2 keyboard and mouse.
-                */
-               if (!strcmp(dev->parent->prom_node->name, "8042")) {
-                       if (!strcmp(dev->prom_node->name, "kb_ps2")) {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[0];
-                       } else {
-                               dev->num_irqs = 1;
-                               dev->irqs[0] = dev->parent->irqs[1];
-                       }
-               }
-       }
-}
-
-static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
-{
-       if (!strcmp(dev->prom_node->name, "i2c") ||
-           !strcmp(dev->prom_node->name, "SUNW,lombus"))
-               return 1;
-       return 0;
-}
-
-static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
-{
-       struct linux_ebus_child *child;
-       struct dev_archdata *sd;
-       struct of_device *op;
-       int i, len;
-
-       dev->prom_node = dp;
-
-       printk(" [%s", dp->name);
-
-       op = of_find_device_by_node(dp);
-       if (!op) {
-               dev->num_addrs = 0;
-               dev->num_irqs = 0;
-       } else {
-               const int *regs = of_get_property(dp, "reg", &len);
-
-               if (!regs)
-                       len = 0;
-               dev->num_addrs = len / sizeof(struct linux_prom_registers);
-
-               for (i = 0; i < dev->num_addrs; i++)
-                       memcpy(&dev->resource[i],
-                              &op->resource[i],
-                              sizeof(struct resource));
-
-               dev->num_irqs = op->num_irqs;
-               for (i = 0; i < dev->num_irqs; i++)
-                       dev->irqs[i] = op->irqs[i];
-       }
-
-       sd = &dev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &dev->ofdev;
-       sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
-       sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
-       sd->numa_node = dev->bus->ofdev.dev.parent->archdata.numa_node;
-
-       dev->ofdev.node = dp;
-       dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
-       dev->ofdev.dev.bus = &ebus_bus_type;
-       dev_set_name(&dev->ofdev.dev, "ebus[%08x]", dp->node);
-
-       /* Register with core */
-       if (of_device_register(&dev->ofdev) != 0)
-               printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       dp = dp->child;
-       if (dp) {
-               printk(" ->");
-               dev->children = ebus_alloc(sizeof(struct linux_ebus_child));
-
-               child = dev->children;
-               child->next = NULL;
-               child->parent = dev;
-               child->bus = dev->bus;
-               fill_ebus_child(dp, child,
-                               child_regs_nonstandard(dev));
-
-               while ((dp = dp->sibling) != NULL) {
-                       child->next = ebus_alloc(sizeof(struct linux_ebus_child));
-
-                       child = child->next;
-                       child->next = NULL;
-                       child->parent = dev;
-                       child->bus = dev->bus;
-                       fill_ebus_child(dp, child,
-                                       child_regs_nonstandard(dev));
-               }
-       }
-       printk("]");
-}
-
-static struct pci_dev *find_next_ebus(struct pci_dev *start, int *is_rio_p)
-{
-       struct pci_dev *pdev = start;
-
-       while ((pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_ANY_ID, pdev)))
-               if (pdev->device == PCI_DEVICE_ID_SUN_EBUS ||
-                       pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS)
-                       break;
-
-       *is_rio_p = !!(pdev && (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS));
-
-       return pdev;
-}
-
-void __init ebus_init(void)
-{
-       struct linux_ebus_device *dev;
-       struct linux_ebus *ebus;
-       struct pci_dev *pdev;
-       struct device_node *dp;
-       int is_rio;
-       int num_ebus = 0;
-
-       pdev = find_next_ebus(NULL, &is_rio);
-       if (!pdev) {
-               printk("ebus: No EBus's found.\n");
-               return;
-       }
-
-       dp = pci_device_to_OF_node(pdev);
-
-       ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus));
-       ebus->next = NULL;
-       ebus->is_rio = is_rio;
-
-       while (dp) {
-               struct device_node *child;
-
-               /* SUNW,pci-qfe uses four empty ebuses on it.
-                  I think we should not consider them here,
-                  as they have half of the properties this
-                  code expects and once we do PCI hot-plug,
-                  we'd have to tweak with the ebus_chain
-                  in the runtime after initialization. -jj */
-               if (!dp->child) {
-                       pdev = find_next_ebus(pdev, &is_rio);
-                       if (!pdev) {
-                               if (ebus == ebus_chain) {
-                                       ebus_chain = NULL;
-                                       printk("ebus: No EBus's found.\n");
-                                       return;
-                               }
-                               break;
-                       }
-                       ebus->is_rio = is_rio;
-                       dp = pci_device_to_OF_node(pdev);
-                       continue;
-               }
-               printk("ebus%d:", num_ebus);
-
-               ebus->index = num_ebus;
-               ebus->prom_node = dp;
-               ebus->self = pdev;
-
-               ebus->ofdev.node = dp;
-               ebus->ofdev.dev.parent = &pdev->dev;
-               ebus->ofdev.dev.bus = &ebus_bus_type;
-               dev_set_name(&ebus->ofdev.dev, "ebus%d", num_ebus);
-
-               /* Register with core */
-               if (of_device_register(&ebus->ofdev) != 0)
-                       printk(KERN_DEBUG "ebus: device registration error for %s!\n",
-                              dp->path_component_name);
-
-
-               child = dp->child;
-               if (!child)
-                       goto next_ebus;
-
-               ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device));
-
-               dev = ebus->devices;
-               dev->next = NULL;
-               dev->children = NULL;
-               dev->bus = ebus;
-               fill_ebus_device(child, dev);
-
-               while ((child = child->sibling) != NULL) {
-                       dev->next = ebus_alloc(sizeof(struct linux_ebus_device));
-
-                       dev = dev->next;
-                       dev->next = NULL;
-                       dev->children = NULL;
-                       dev->bus = ebus;
-                       fill_ebus_device(child, dev);
-               }
-
-       next_ebus:
-               printk("\n");
-
-               pdev = find_next_ebus(pdev, &is_rio);
-               if (!pdev)
-                       break;
-
-               dp = pci_device_to_OF_node(pdev);
-
-               ebus->next = ebus_alloc(sizeof(struct linux_ebus));
-               ebus = ebus->next;
-               ebus->next = NULL;
-               ebus->is_rio = is_rio;
-               ++num_ebus;
-       }
-       pci_dev_put(pdev); /* XXX for the case, when ebusnd is 0, is it OK? */
-}
index fc294a292899ee383906e5040e2509907776527e..34d7ab5e10d23c7e0023fa31af791814e341b95d 100644 (file)
@@ -5,8 +5,8 @@
 #include <linux/types.h>
 #include <linux/init.h>
 
-extern char *sparc_cpu_type;
-extern char *sparc_fpu_type;
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
 
 extern void __init per_cpu_patch(void);
 extern void __init sun4v_patch(void);
@@ -22,7 +22,8 @@ extern void do_notify_resume(struct pt_regs *regs,
                             unsigned long orig_i0,
                             unsigned long thread_info_flags);
 
-extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p);
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
 
index c9afef093d51b3aceed553bd0ad2c21c0858d565..353226fa023991240653fadf8504b958dc4529ae 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/errno.h>
 #include <linux/threads.h>
 #include <linux/init.h>
+#include <linux/linkage.h>
 #include <asm/thread_info.h>
 #include <asm/asi.h>
 #include <asm/pstate.h>
index 691760b5b0127e5143da2bfa4056ac63e86ba238..1d272c3b574084d7c8eb52a45dae241315b10261 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <asm/hypervisor.h>
 #include <asm/oplib.h>
-#include <asm/sstate.h>
 
 /* If the hypervisor indicates that the API setting
  * calls are unsupported, by returning HV_EBADTRAP or
@@ -184,8 +183,6 @@ void __init sun4v_hvapi_init(void)
        if (sun4v_hvapi_register(group, major, &minor))
                goto bad;
 
-       sun4v_sstate_init();
-
        return;
 
 bad:
index a2810f3ac70f2b5df536ae04c3e58dcd35dfbb81..e066269d1594191c00c9405e21b8eb24ae915a3d 100644 (file)
@@ -3,89 +3,75 @@
         *
         * returns %o0: sysino
         */
-       .globl  sun4v_devino_to_sysino
-       .type   sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
+ENTRY(sun4v_devino_to_sysino)
        mov     HV_FAST_INTR_DEVINO2SYSINO, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+ENDPROC(sun4v_devino_to_sysino)
 
        /* %o0: sysino
         *
         * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
         */
-       .globl  sun4v_intr_getenabled
-       .type   sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
+ENTRY(sun4v_intr_getenabled)
        mov     HV_FAST_INTR_GETENABLED, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_getenabled, .-sun4v_intr_getenabled
+ENDPROC(sun4v_intr_getenabled)
 
        /* %o0: sysino
         * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
         */
-       .globl  sun4v_intr_setenabled
-       .type   sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
+ENTRY(sun4v_intr_setenabled)
        mov     HV_FAST_INTR_SETENABLED, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_setenabled, .-sun4v_intr_setenabled
+ENDPROC(sun4v_intr_setenabled)
 
        /* %o0: sysino
         *
         * returns %o0: intr_state (HV_INTR_STATE_*)
         */
-       .globl  sun4v_intr_getstate
-       .type   sun4v_intr_getstate,#function
-sun4v_intr_getstate:
+ENTRY(sun4v_intr_getstate)
        mov     HV_FAST_INTR_GETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_getstate, .-sun4v_intr_getstate
+ENDPROC(sun4v_intr_getstate)
 
        /* %o0: sysino
         * %o1: intr_state (HV_INTR_STATE_*)
         */
-       .globl  sun4v_intr_setstate
-       .type   sun4v_intr_setstate,#function
-sun4v_intr_setstate:
+ENTRY(sun4v_intr_setstate)
        mov     HV_FAST_INTR_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_setstate, .-sun4v_intr_setstate
+ENDPROC(sun4v_intr_setstate)
 
        /* %o0: sysino
         *
         * returns %o0: cpuid
         */
-       .globl  sun4v_intr_gettarget
-       .type   sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
+ENTRY(sun4v_intr_gettarget)
        mov     HV_FAST_INTR_GETTARGET, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
-       .size   sun4v_intr_gettarget, .-sun4v_intr_gettarget
+ENDPROC(sun4v_intr_gettarget)
 
        /* %o0: sysino
         * %o1: cpuid
         */
-       .globl  sun4v_intr_settarget
-       .type   sun4v_intr_settarget,#function
-sun4v_intr_settarget:
+ENTRY(sun4v_intr_settarget)
        mov     HV_FAST_INTR_SETTARGET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_intr_settarget, .-sun4v_intr_settarget
+ENDPROC(sun4v_intr_settarget)
 
        /* %o0: cpuid
         * %o1: pc
@@ -94,37 +80,31 @@ sun4v_intr_settarget:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_start
-       .type   sun4v_cpu_start,#function
-sun4v_cpu_start:
+ENTRY(sun4v_cpu_start)
        mov     HV_FAST_CPU_START, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_start, .-sun4v_cpu_start
+ENDPROC(sun4v_cpu_start)
 
        /* %o0: cpuid
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_stop
-       .type   sun4v_cpu_stop,#function
-sun4v_cpu_stop:
+ENTRY(sun4v_cpu_stop)
        mov     HV_FAST_CPU_STOP, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_stop, .-sun4v_cpu_stop
+ENDPROC(sun4v_cpu_stop)
 
        /* returns %o0: status  */
-       .globl  sun4v_cpu_yield
-       .type   sun4v_cpu_yield, #function
-sun4v_cpu_yield:
+ENTRY(sun4v_cpu_yield)
        mov     HV_FAST_CPU_YIELD, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_yield, .-sun4v_cpu_yield
+ENDPROC(sun4v_cpu_yield)
 
        /* %o0: type
         * %o1: queue paddr
@@ -132,14 +112,12 @@ sun4v_cpu_yield:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_qconf
-       .type   sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
+ENTRY(sun4v_cpu_qconf)
        mov     HV_FAST_CPU_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_qconf, .-sun4v_cpu_qconf
+ENDPROC(sun4v_cpu_qconf)
 
        /* %o0: num cpus in cpu list
         * %o1: cpu list paddr
@@ -147,23 +125,19 @@ sun4v_cpu_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_cpu_mondo_send
-       .type   sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
+ENTRY(sun4v_cpu_mondo_send)
        mov     HV_FAST_CPU_MONDO_SEND, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+ENDPROC(sun4v_cpu_mondo_send)
 
        /* %o0: CPU ID
         *
         * returns %o0: -status if status non-zero, else
         *         %o0: cpu state as HV_CPU_STATE_*
         */
-       .globl  sun4v_cpu_state
-       .type   sun4v_cpu_state,#function
-sun4v_cpu_state:
+ENTRY(sun4v_cpu_state)
        mov     HV_FAST_CPU_STATE, %o5
        ta      HV_FAST_TRAP
        brnz,pn %o0, 1f
@@ -171,7 +145,7 @@ sun4v_cpu_state:
        mov     %o1, %o0
 1:     retl
         nop
-       .size   sun4v_cpu_state, .-sun4v_cpu_state
+ENDPROC(sun4v_cpu_state)
 
        /* %o0: virtual address
         * %o1: must be zero
@@ -180,28 +154,24 @@ sun4v_cpu_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_mmu_map_perm_addr
-       .type   sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
+ENTRY(sun4v_mmu_map_perm_addr)
        mov     HV_FAST_MMU_MAP_PERM_ADDR, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+ENDPROC(sun4v_mmu_map_perm_addr)
 
        /* %o0: number of TSB descriptions
         * %o1: TSB descriptions real address
         *
         * returns %o0: status
         */
-       .globl  sun4v_mmu_tsb_ctx0
-       .type   sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
+ENTRY(sun4v_mmu_tsb_ctx0)
        mov     HV_FAST_MMU_TSB_CTX0, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+ENDPROC(sun4v_mmu_tsb_ctx0)
 
        /* %o0: API group number
         * %o1: pointer to unsigned long major number storage
@@ -209,9 +179,7 @@ sun4v_mmu_tsb_ctx0:
         *
         * returns %o0: status
         */
-       .globl  sun4v_get_version
-       .type   sun4v_get_version,#function
-sun4v_get_version:
+ENTRY(sun4v_get_version)
        mov     HV_CORE_GET_VER, %o5
        mov     %o1, %o3
        mov     %o2, %o4
@@ -219,7 +187,7 @@ sun4v_get_version:
        stx     %o1, [%o3]
        retl
         stx    %o2, [%o4]
-       .size   sun4v_get_version, .-sun4v_get_version
+ENDPROC(sun4v_get_version)
 
        /* %o0: API group number
         * %o1: desired major number
@@ -228,51 +196,43 @@ sun4v_get_version:
         *
         * returns %o0: status
         */
-       .globl  sun4v_set_version
-       .type   sun4v_set_version,#function
-sun4v_set_version:
+ENTRY(sun4v_set_version)
        mov     HV_CORE_SET_VER, %o5
        mov     %o3, %o4
        ta      HV_CORE_TRAP
        retl
         stx    %o1, [%o4]
-       .size   sun4v_set_version, .-sun4v_set_version
+ENDPROC(sun4v_set_version)
 
        /* %o0: pointer to unsigned long time
         *
         * returns %o0: status
         */
-       .globl  sun4v_tod_get
-       .type   sun4v_tod_get,#function
-sun4v_tod_get:
+ENTRY(sun4v_tod_get)
        mov     %o0, %o4
        mov     HV_FAST_TOD_GET, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_tod_get, .-sun4v_tod_get
+ENDPROC(sun4v_tod_get)
 
        /* %o0: time
         *
         * returns %o0: status
         */
-       .globl  sun4v_tod_set
-       .type   sun4v_tod_set,#function
-sun4v_tod_set:
+ENTRY(sun4v_tod_set)
        mov     HV_FAST_TOD_SET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_tod_set, .-sun4v_tod_set
+ENDPROC(sun4v_tod_set)
 
        /* %o0: pointer to unsigned long status
         *
         * returns %o0: signed character
         */
-       .globl  sun4v_con_getchar
-       .type   sun4v_con_getchar,#function
-sun4v_con_getchar:
+ENTRY(sun4v_con_getchar)
        mov     %o0, %o4
        mov     HV_FAST_CONS_GETCHAR, %o5
        clr     %o0
@@ -281,20 +241,18 @@ sun4v_con_getchar:
        stx     %o0, [%o4]
        retl
         sra    %o1, 0, %o0
-       .size   sun4v_con_getchar, .-sun4v_con_getchar
+ENDPROC(sun4v_con_getchar)
 
        /* %o0: signed long character
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_putchar
-       .type   sun4v_con_putchar,#function
-sun4v_con_putchar:
+ENTRY(sun4v_con_putchar)
        mov     HV_FAST_CONS_PUTCHAR, %o5
        ta      HV_FAST_TRAP
        retl
         sra    %o0, 0, %o0
-       .size   sun4v_con_putchar, .-sun4v_con_putchar
+ENDPROC(sun4v_con_putchar)
 
        /* %o0: buffer real address
         * %o1: buffer size
@@ -302,9 +260,7 @@ sun4v_con_putchar:
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_read
-       .type   sun4v_con_read,#function
-sun4v_con_read:
+ENTRY(sun4v_con_read)
        mov     %o2, %o4
        mov     HV_FAST_CONS_READ, %o5
        ta      HV_FAST_TRAP
@@ -318,7 +274,7 @@ sun4v_con_read:
        stx     %o1, [%o4]
 1:     retl
         nop
-       .size   sun4v_con_read, .-sun4v_con_read
+ENDPROC(sun4v_con_read)
 
        /* %o0: buffer real address
         * %o1: buffer size
@@ -326,43 +282,37 @@ sun4v_con_read:
         *
         * returns %o0: status
         */
-       .globl  sun4v_con_write
-       .type   sun4v_con_write,#function
-sun4v_con_write:
+ENTRY(sun4v_con_write)
        mov     %o2, %o4
        mov     HV_FAST_CONS_WRITE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_con_write, .-sun4v_con_write
+ENDPROC(sun4v_con_write)
 
        /* %o0: soft state
         * %o1: address of description string
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_set_soft_state
-       .type   sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
+ENTRY(sun4v_mach_set_soft_state)
        mov     HV_FAST_MACH_SET_SOFT_STATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+ENDPROC(sun4v_mach_set_soft_state)
 
        /* %o0: exit code
         *
         * Does not return.
         */
-       .globl  sun4v_mach_exit
-       .type   sun4v_mach_exit,#function
-sun4v_mach_exit:
+ENTRY(sun4v_mach_exit)
        mov     HV_FAST_MACH_EXIT, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mach_exit, .-sun4v_mach_exit
+ENDPROC(sun4v_mach_exit)
 
        /* %o0: buffer real address
         * %o1: buffer length
@@ -370,44 +320,38 @@ sun4v_mach_exit:
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_desc
-       .type   sun4v_mach_desc,#function
-sun4v_mach_desc:
+ENTRY(sun4v_mach_desc)
        mov     %o2, %o4
        mov     HV_FAST_MACH_DESC, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_desc, .-sun4v_mach_desc
+ENDPROC(sun4v_mach_desc)
 
        /* %o0: new timeout in milliseconds
         * %o1: pointer to unsigned long orig_timeout
         *
         * returns %o0: status
         */
-       .globl  sun4v_mach_set_watchdog
-       .type   sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
+ENTRY(sun4v_mach_set_watchdog)
        mov     %o1, %o4
        mov     HV_FAST_MACH_SET_WATCHDOG, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+ENDPROC(sun4v_mach_set_watchdog)
 
        /* No inputs and does not return.  */
-       .globl  sun4v_mach_sir
-       .type   sun4v_mach_sir,#function
-sun4v_mach_sir:
+ENTRY(sun4v_mach_sir)
        mov     %o1, %o4
        mov     HV_FAST_MACH_SIR, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mach_sir, .-sun4v_mach_sir
+ENDPROC(sun4v_mach_sir)
 
        /* %o0: channel
         * %o1: ra
@@ -415,14 +359,12 @@ sun4v_mach_sir:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_qconf
-       .type   sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
+ENTRY(sun4v_ldc_tx_qconf)
        mov     HV_FAST_LDC_TX_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+ENDPROC(sun4v_ldc_tx_qconf)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -430,9 +372,7 @@ sun4v_ldc_tx_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_qinfo
-       .type   sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
+ENTRY(sun4v_ldc_tx_qinfo)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_TX_QINFO, %o5
@@ -441,7 +381,7 @@ sun4v_ldc_tx_qinfo:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+ENDPROC(sun4v_ldc_tx_qinfo)
 
        /* %o0: channel
         * %o1: pointer to unsigned long head_off
@@ -450,9 +390,7 @@ sun4v_ldc_tx_qinfo:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_get_state
-       .type   sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
+ENTRY(sun4v_ldc_tx_get_state)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     %o3, %g3
@@ -463,21 +401,19 @@ sun4v_ldc_tx_get_state:
        stx     %o3, [%g3]
        retl
         nop
-       .size   sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+ENDPROC(sun4v_ldc_tx_get_state)
 
        /* %o0: channel
         * %o1: tail_off
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_tx_set_qtail
-       .type   sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
+ENTRY(sun4v_ldc_tx_set_qtail)
        mov     HV_FAST_LDC_TX_SET_QTAIL, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+ENDPROC(sun4v_ldc_tx_set_qtail)
 
        /* %o0: channel
         * %o1: ra
@@ -485,14 +421,12 @@ sun4v_ldc_tx_set_qtail:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_qconf
-       .type   sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
+ENTRY(sun4v_ldc_rx_qconf)
        mov     HV_FAST_LDC_RX_QCONF, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+ENDPROC(sun4v_ldc_rx_qconf)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -500,9 +434,7 @@ sun4v_ldc_rx_qconf:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_qinfo
-       .type   sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
+ENTRY(sun4v_ldc_rx_qinfo)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_RX_QINFO, %o5
@@ -511,7 +443,7 @@ sun4v_ldc_rx_qinfo:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+ENDPROC(sun4v_ldc_rx_qinfo)
 
        /* %o0: channel
         * %o1: pointer to unsigned long head_off
@@ -520,9 +452,7 @@ sun4v_ldc_rx_qinfo:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_get_state
-       .type   sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
+ENTRY(sun4v_ldc_rx_get_state)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     %o3, %g3
@@ -533,21 +463,19 @@ sun4v_ldc_rx_get_state:
        stx     %o3, [%g3]
        retl
         nop
-       .size   sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+ENDPROC(sun4v_ldc_rx_get_state)
 
        /* %o0: channel
         * %o1: head_off
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_rx_set_qhead
-       .type   sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
+ENTRY(sun4v_ldc_rx_set_qhead)
        mov     HV_FAST_LDC_RX_SET_QHEAD, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+ENDPROC(sun4v_ldc_rx_set_qhead)
 
        /* %o0: channel
         * %o1: ra
@@ -555,14 +483,12 @@ sun4v_ldc_rx_set_qhead:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_set_map_table
-       .type   sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
+ENTRY(sun4v_ldc_set_map_table)
        mov     HV_FAST_LDC_SET_MAP_TABLE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+ENDPROC(sun4v_ldc_set_map_table)
 
        /* %o0: channel
         * %o1: pointer to unsigned long ra
@@ -570,9 +496,7 @@ sun4v_ldc_set_map_table:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_get_map_table
-       .type   sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
+ENTRY(sun4v_ldc_get_map_table)
        mov     %o1, %g1
        mov     %o2, %g2
        mov     HV_FAST_LDC_GET_MAP_TABLE, %o5
@@ -581,7 +505,7 @@ sun4v_ldc_get_map_table:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+ENDPROC(sun4v_ldc_get_map_table)
 
        /* %o0: channel
         * %o1: dir_code
@@ -592,16 +516,14 @@ sun4v_ldc_get_map_table:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_copy
-       .type   sun4v_ldc_copy,#function
-sun4v_ldc_copy:
+ENTRY(sun4v_ldc_copy)
        mov     %o5, %g1
        mov     HV_FAST_LDC_COPY, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_ldc_copy, .-sun4v_ldc_copy
+ENDPROC(sun4v_ldc_copy)
 
        /* %o0: channel
         * %o1: cookie
@@ -610,9 +532,7 @@ sun4v_ldc_copy:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_mapin
-       .type   sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
+ENTRY(sun4v_ldc_mapin)
        mov     %o2, %g1
        mov     %o3, %g2
        mov     HV_FAST_LDC_MAPIN, %o5
@@ -621,20 +541,18 @@ sun4v_ldc_mapin:
        stx     %o2, [%g2]
        retl
         nop
-       .size   sun4v_ldc_mapin, .-sun4v_ldc_mapin
+ENDPROC(sun4v_ldc_mapin)
 
        /* %o0: ra
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_unmap
-       .type   sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
+ENTRY(sun4v_ldc_unmap)
        mov     HV_FAST_LDC_UNMAP, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_unmap, .-sun4v_ldc_unmap
+ENDPROC(sun4v_ldc_unmap)
 
        /* %o0: channel
         * %o1: cookie
@@ -642,14 +560,12 @@ sun4v_ldc_unmap:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ldc_revoke
-       .type   sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
+ENTRY(sun4v_ldc_revoke)
        mov     HV_FAST_LDC_REVOKE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ldc_revoke, .-sun4v_ldc_revoke
+ENDPROC(sun4v_ldc_revoke)
 
        /* %o0: device handle
         * %o1: device INO
@@ -657,16 +573,14 @@ sun4v_ldc_revoke:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_cookie
-       .type   sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
+ENTRY(sun4v_vintr_get_cookie)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_COOKIE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+ENDPROC(sun4v_vintr_get_cookie)
 
        /* %o0: device handle
         * %o1: device INO
@@ -674,14 +588,12 @@ sun4v_vintr_get_cookie:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_cookie
-       .type   sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
+ENTRY(sun4v_vintr_set_cookie)
        mov     HV_FAST_VINTR_SET_COOKIE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+ENDPROC(sun4v_vintr_set_cookie)
 
        /* %o0: device handle
         * %o1: device INO
@@ -689,16 +601,14 @@ sun4v_vintr_set_cookie:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_valid
-       .type   sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
+ENTRY(sun4v_vintr_get_valid)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_VALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+ENDPROC(sun4v_vintr_get_valid)
 
        /* %o0: device handle
         * %o1: device INO
@@ -706,14 +616,12 @@ sun4v_vintr_get_valid:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_valid
-       .type   sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
+ENTRY(sun4v_vintr_set_valid)
        mov     HV_FAST_VINTR_SET_VALID, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+ENDPROC(sun4v_vintr_set_valid)
 
        /* %o0: device handle
         * %o1: device INO
@@ -721,16 +629,14 @@ sun4v_vintr_set_valid:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_state
-       .type   sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
+ENTRY(sun4v_vintr_get_state)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_STATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_state, .-sun4v_vintr_get_state
+ENDPROC(sun4v_vintr_get_state)
 
        /* %o0: device handle
         * %o1: device INO
@@ -738,14 +644,12 @@ sun4v_vintr_get_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_state
-       .type   sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
+ENTRY(sun4v_vintr_set_state)
        mov     HV_FAST_VINTR_SET_STATE, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_state, .-sun4v_vintr_set_state
+ENDPROC(sun4v_vintr_set_state)
 
        /* %o0: device handle
         * %o1: device INO
@@ -753,16 +657,14 @@ sun4v_vintr_set_state:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_get_target
-       .type   sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
+ENTRY(sun4v_vintr_get_target)
        mov     %o2, %g1
        mov     HV_FAST_VINTR_GET_TARGET, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%g1]
        retl
         nop
-       .size   sun4v_vintr_get_target, .-sun4v_vintr_get_target
+ENDPROC(sun4v_vintr_get_target)
 
        /* %o0: device handle
         * %o1: device INO
@@ -770,14 +672,12 @@ sun4v_vintr_get_target:
         *
         * returns %o0: status
         */
-       .globl  sun4v_vintr_set_target
-       .type   sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
+ENTRY(sun4v_vintr_set_target)
        mov     HV_FAST_VINTR_SET_TARGET, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_vintr_set_target, .-sun4v_vintr_set_target
+ENDPROC(sun4v_vintr_set_target)
 
        /* %o0: NCS sub-function
         * %o1: sub-function arg real-address
@@ -785,18 +685,14 @@ sun4v_vintr_set_target:
         *
         * returns %o0: status
         */
-       .globl  sun4v_ncs_request
-       .type   sun4v_ncs_request,#function
-sun4v_ncs_request:
+ENTRY(sun4v_ncs_request)
        mov     HV_FAST_NCS_REQUEST, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_ncs_request, .-sun4v_ncs_request
+ENDPROC(sun4v_ncs_request)
 
-       .globl  sun4v_svc_send
-       .type   sun4v_svc_send,#function
-sun4v_svc_send:
+ENTRY(sun4v_svc_send)
        save    %sp, -192, %sp
        mov     %i0, %o0
        mov     %i1, %o1
@@ -806,11 +702,9 @@ sun4v_svc_send:
        stx     %o1, [%i3]
        ret
        restore
-       .size   sun4v_svc_send, .-sun4v_svc_send
+ENDPROC(sun4v_svc_send)
 
-       .globl  sun4v_svc_recv
-       .type   sun4v_svc_recv,#function
-sun4v_svc_recv:
+ENTRY(sun4v_svc_recv)
        save    %sp, -192, %sp
        mov     %i0, %o0
        mov     %i1, %o1
@@ -820,62 +714,50 @@ sun4v_svc_recv:
        stx     %o1, [%i3]
        ret
        restore
-       .size   sun4v_svc_recv, .-sun4v_svc_recv
+ENDPROC(sun4v_svc_recv)
 
-       .globl  sun4v_svc_getstatus
-       .type   sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
+ENTRY(sun4v_svc_getstatus)
        mov     HV_FAST_SVC_GETSTATUS, %o5
        mov     %o1, %o4
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_svc_getstatus, .-sun4v_svc_getstatus
+ENDPROC(sun4v_svc_getstatus)
 
-       .globl  sun4v_svc_setstatus
-       .type   sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
+ENTRY(sun4v_svc_setstatus)
        mov     HV_FAST_SVC_SETSTATUS, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_svc_setstatus, .-sun4v_svc_setstatus
+ENDPROC(sun4v_svc_setstatus)
 
-       .globl  sun4v_svc_clrstatus
-       .type   sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
+ENTRY(sun4v_svc_clrstatus)
        mov     HV_FAST_SVC_CLRSTATUS, %o5
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+ENDPROC(sun4v_svc_clrstatus)
 
-       .globl  sun4v_mmustat_conf
-       .type   sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
+ENTRY(sun4v_mmustat_conf)
        mov     %o1, %o4
        mov     HV_FAST_MMUSTAT_CONF, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mmustat_conf, .-sun4v_mmustat_conf
+ENDPROC(sun4v_mmustat_conf)
 
-       .globl  sun4v_mmustat_info
-       .type   sun4v_mmustat_info,#function
-sun4v_mmustat_info:
+ENTRY(sun4v_mmustat_info)
        mov     %o0, %o4
        mov     HV_FAST_MMUSTAT_INFO, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o4]
        retl
         nop
-       .size   sun4v_mmustat_info, .-sun4v_mmustat_info
+ENDPROC(sun4v_mmustat_info)
 
-       .globl  sun4v_mmu_demap_all
-       .type   sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
+ENTRY(sun4v_mmu_demap_all)
        clr     %o0
        clr     %o1
        mov     HV_MMU_ALL, %o2
@@ -883,4 +765,4 @@ sun4v_mmu_demap_all:
        ta      HV_FAST_TRAP
        retl
         nop
-       .size   sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
+ENDPROC(sun4v_mmu_demap_all)
index 7495bc774685d53df0385bebec0cad80e4a9e27d..52fc836f464d979655c330b43b15736fc6c840a2 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/system.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/iommu.h>
 #include <asm/upa.h>
 #include <asm/oplib.h>
index 100ebd527499991f39b094709fe597fa77f571f6..0f616ae3246c5a9bc4be334f52c2879fead932f2 100644 (file)
@@ -55,15 +55,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
 }
 EXPORT_SYMBOL(of_find_device_by_node);
 
-#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type;
-EXPORT_SYMBOL(ebus_bus_type);
-#endif
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
 
-#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type;
-EXPORT_SYMBOL(sbus_bus_type);
-#endif
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
 
 struct bus_type of_platform_bus_type;
 EXPORT_SYMBOL(of_platform_bus_type);
@@ -378,8 +401,7 @@ static int __init build_one_resource(struct device_node *parent,
                                     int na, int ns, int pna)
 {
        const u32 *ranges;
-       unsigned int rlen;
-       int rone;
+       int rone, rlen;
 
        ranges = of_get_property(parent, "ranges", &rlen);
        if (ranges == NULL || rlen == 0) {
@@ -421,8 +443,17 @@ static int __init use_1to1_mapping(struct device_node *pp)
 
        /* If the parent is the dma node of an ISA bus, pass
         * the translation up to the root.
+        *
+        * Some SBUS devices use intermediate nodes to express
+        * hierarchy within the device itself.  These aren't
+        * real bus nodes, and don't have a 'ranges' property.
+        * But, we should still pass the translation work up
+        * to the SBUS itself.
         */
-       if (!strcmp(pp->name, "dma"))
+       if (!strcmp(pp->name, "dma") ||
+           !strcmp(pp->name, "espdma") ||
+           !strcmp(pp->name, "ledma") ||
+           !strcmp(pp->name, "lebuffer"))
                return 0;
 
        /* Similarly for all PCI bridges, if we get this far
@@ -844,15 +875,6 @@ static int __init of_bus_driver_init(void)
        int err;
 
        err = of_bus_type_init(&of_platform_bus_type, "of");
-#ifdef CONFIG_PCI
-       if (!err)
-               err = of_bus_type_init(&ebus_bus_type, "ebus");
-#endif
-#ifdef CONFIG_SBUS
-       if (!err)
-               err = of_bus_type_init(&sbus_bus_type, "sbus");
-#endif
-
        if (!err)
                scan_of_devices();
 
index 80dad76f8b81c24b55cc3d26177cae9b7fa7ca79..242ac1ccae7d5866b3beac630780cf501cb26f45 100644 (file)
 #include <linux/msi.h>
 #include <linux/irq.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
-#include <asm/ebus.h>
 #include <asm/prom.h>
 #include <asm/apb.h>
 
 #include "pci_impl.h"
 
-#ifndef CONFIG_PCI
-/* A "nop" PCI implementation. */
-asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
-                                 unsigned long off, unsigned long len,
-                                 unsigned char *buf)
-{
-       return 0;
-}
-asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn,
-                                  unsigned long off, unsigned long len,
-                                  unsigned char *buf)
-{
-       return 0;
-}
-#else
-
 /* List of all PCI controllers found in the system. */
 struct pci_pbm_info *pci_pbm_root = NULL;
 
@@ -179,97 +164,6 @@ void pci_config_write32(u32 *addr, u32 val)
        spin_unlock_irqrestore(&pci_poke_lock, flags);
 }
 
-/* Probe for all PCI controllers in the system. */
-extern void sabre_init(struct device_node *, const char *);
-extern void psycho_init(struct device_node *, const char *);
-extern void schizo_init(struct device_node *, const char *);
-extern void schizo_plus_init(struct device_node *, const char *);
-extern void tomatillo_init(struct device_node *, const char *);
-extern void sun4v_pci_init(struct device_node *, const char *);
-extern void fire_pci_init(struct device_node *, const char *);
-
-static struct {
-       char *model_name;
-       void (*init)(struct device_node *, const char *);
-} pci_controller_table[] __initdata = {
-       { "SUNW,sabre", sabre_init },
-       { "pci108e,a000", sabre_init },
-       { "pci108e,a001", sabre_init },
-       { "SUNW,psycho", psycho_init },
-       { "pci108e,8000", psycho_init },
-       { "SUNW,schizo", schizo_init },
-       { "pci108e,8001", schizo_init },
-       { "SUNW,schizo+", schizo_plus_init },
-       { "pci108e,8002", schizo_plus_init },
-       { "SUNW,tomatillo", tomatillo_init },
-       { "pci108e,a801", tomatillo_init },
-       { "SUNW,sun4v-pci", sun4v_pci_init },
-       { "pciex108e,80f0", fire_pci_init },
-};
-#define PCI_NUM_CONTROLLER_TYPES       ARRAY_SIZE(pci_controller_table)
-
-static int __init pci_controller_init(const char *model_name, int namelen, struct device_node *dp)
-{
-       int i;
-
-       for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) {
-               if (!strncmp(model_name,
-                            pci_controller_table[i].model_name,
-                            namelen)) {
-                       pci_controller_table[i].init(dp, model_name);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-static int __init pci_controller_scan(int (*handler)(const char *, int, struct device_node *))
-{
-       struct device_node *dp;
-       int count = 0;
-
-       for_each_node_by_name(dp, "pci") {
-               struct property *prop;
-               int len;
-
-               prop = of_find_property(dp, "model", &len);
-               if (!prop)
-                       prop = of_find_property(dp, "compatible", &len);
-
-               if (prop) {
-                       const char *model = prop->value;
-                       int item_len = 0;
-
-                       /* Our value may be a multi-valued string in the
-                        * case of some compatible properties. For sanity,
-                        * only try the first one.
-                        */
-                       while (model[item_len] && len) {
-                               len--;
-                               item_len++;
-                       }
-
-                       if (handler(model, item_len, dp))
-                               count++;
-               }
-       }
-
-       return count;
-}
-
-/* Find each controller in the system, attach and initialize
- * software state structure for each and link into the
- * pci_pbm_root.  Setup the controller enough such
- * that bus scanning can be done.
- */
-static void __init pci_controller_probe(void)
-{
-       printk("PCI: Probing for controllers.\n");
-
-       pci_controller_scan(pci_controller_init);
-}
-
 static int ofpci_verbose;
 
 static int __init ofpci_debug(char *str)
@@ -348,11 +242,12 @@ static void pci_parse_of_addrs(struct of_device *op,
        }
 }
 
-struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
-                                 struct device_node *node,
-                                 struct pci_bus *bus, int devfn)
+static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
+                                        struct device_node *node,
+                                        struct pci_bus *bus, int devfn)
 {
        struct dev_archdata *sd;
+       struct of_device *op;
        struct pci_dev *dev;
        const char *type;
        u32 class;
@@ -366,14 +261,17 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        sd->stc = &pbm->stc;
        sd->host_controller = pbm;
        sd->prom_node = node;
-       sd->op = of_find_device_by_node(node);
+       sd->op = op = of_find_device_by_node(node);
        sd->numa_node = pbm->numa_node;
 
-       sd = &sd->op->dev.archdata;
+       sd = &op->dev.archdata;
        sd->iommu = pbm->iommu;
        sd->stc = &pbm->stc;
        sd->numa_node = pbm->numa_node;
 
+       if (!strcmp(node->name, "ebus"))
+               of_propagate_archdata(op);
+
        type = of_get_property(node, "device_type", NULL);
        if (type == NULL)
                type = "";
@@ -775,15 +673,15 @@ static void __devinit pci_bus_register_of_sysfs(struct pci_bus *bus)
                pci_bus_register_of_sysfs(child_bus);
 }
 
-struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
+struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm,
+                                           struct device *parent)
 {
-       struct device_node *node = pbm->prom_node;
+       struct device_node *node = pbm->op->node;
        struct pci_bus *bus;
 
        printk("PCI: Scanning PBM %s\n", node->full_name);
 
-       /* XXX parent device? XXX */
-       bus = pci_create_bus(NULL, pbm->pci_first_busno, pbm->pci_ops, pbm);
+       bus = pci_create_bus(parent, pbm->pci_first_busno, pbm->pci_ops, pbm);
        if (!bus) {
                printk(KERN_ERR "Failed to create bus for %s\n",
                       node->full_name);
@@ -802,32 +700,6 @@ struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
        return bus;
 }
 
-static void __init pci_scan_each_controller_bus(void)
-{
-       struct pci_pbm_info *pbm;
-
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next)
-               pbm->scan_bus(pbm);
-}
-
-extern void power_init(void);
-
-static int __init pcibios_init(void)
-{
-       pci_controller_probe();
-       if (pci_pbm_root == NULL)
-               return 0;
-
-       pci_scan_each_controller_bus();
-
-       ebus_init();
-       power_init();
-
-       return 0;
-}
-
-subsys_initcall(pcibios_init);
-
 void __devinit pcibios_fixup_bus(struct pci_bus *pbus)
 {
        struct pci_pbm_info *pbm = pbus->sysdata;
@@ -1105,14 +977,14 @@ int pcibus_to_node(struct pci_bus *pbus)
 EXPORT_SYMBOL(pcibus_to_node);
 #endif
 
-/* Return the domain nuber for this pci bus */
+/* Return the domain number for this pci bus */
 
 int pci_domain_nr(struct pci_bus *pbus)
 {
        struct pci_pbm_info *pbm = pbus->sysdata;
        int ret;
 
-       if (pbm == NULL || pbm->parent == NULL) {
+       if (!pbm) {
                ret = -ENXIO;
        } else {
                ret = pbm->index;
@@ -1126,7 +998,7 @@ EXPORT_SYMBOL(pci_domain_nr);
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       int virt_irq;
+       unsigned int virt_irq;
 
        if (!pbm->setup_msi_irq)
                return -EINVAL;
@@ -1140,10 +1012,8 @@ void arch_teardown_msi_irq(unsigned int virt_irq)
        struct pci_dev *pdev = entry->dev;
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
 
-       if (!pbm->teardown_msi_irq)
-               return;
-
-       return pbm->teardown_msi_irq(virt_irq, pdev);
+       if (pbm->teardown_msi_irq)
+               pbm->teardown_msi_irq(virt_irq, pdev);
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
@@ -1215,5 +1085,3 @@ void pci_resource_to_user(const struct pci_dev *pdev, int bar,
        *start = rp->start - offset;
        *end = rp->end - offset;
 }
-
-#endif /* !(CONFIG_PCI) */
index 09a5ec200c61d3fda984af889600159ff2d953b4..23b88082d0b28d72c639f65582194094c84c2a24 100644 (file)
@@ -314,12 +314,12 @@ struct pci_ops sun4v_pci_ops = {
 
 void pci_get_pbm_props(struct pci_pbm_info *pbm)
 {
-       const u32 *val = of_get_property(pbm->prom_node, "bus-range", NULL);
+       const u32 *val = of_get_property(pbm->op->node, "bus-range", NULL);
 
        pbm->pci_first_busno = val[0];
        pbm->pci_last_busno = val[1];
 
-       val = of_get_property(pbm->prom_node, "ino-bitmap", NULL);
+       val = of_get_property(pbm->op->node, "ino-bitmap", NULL);
        if (val) {
                pbm->ino_bitmap = (((u64)val[1] << 32UL) |
                                   ((u64)val[0] <<  0UL));
@@ -365,7 +365,7 @@ static void pci_register_legacy_regions(struct resource *io_res,
 
 static void pci_register_iommu_region(struct pci_pbm_info *pbm)
 {
-       const u32 *vdma = of_get_property(pbm->prom_node, "virtual-dma", NULL);
+       const u32 *vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
 
        if (vdma) {
                struct resource *rp = kmalloc(sizeof(*rp), GFP_KERNEL);
@@ -389,7 +389,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
        int num_pbm_ranges;
 
        saw_mem = saw_io = 0;
-       pbm_ranges = of_get_property(pbm->prom_node, "ranges", &i);
+       pbm_ranges = of_get_property(pbm->op->node, "ranges", &i);
        if (!pbm_ranges) {
                prom_printf("PCI: Fatal error, missing PBM ranges property "
                            " for %s\n",
index d23bb6f53cdac8e09225f7a8b95c01f6d40a38be..9462b68f489415f631702baaeef8935246def172 100644 (file)
@@ -8,34 +8,16 @@
 #include <linux/init.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
+#include <linux/of_device.h>
 
-#include <asm/oplib.h>
 #include <asm/prom.h>
 #include <asm/irq.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 
-#define fire_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define fire_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
-
-static void __init pci_fire_scan_bus(struct pci_pbm_info *pbm)
-{
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
-
-       /* XXX register error interrupt handlers XXX */
-}
+#define DRIVER_NAME    "fire"
+#define PFX            DRIVER_NAME ": "
 
 #define FIRE_IOMMU_CONTROL     0x40000UL
 #define FIRE_IOMMU_TSBBASE     0x40008UL
@@ -69,21 +51,21 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
        /*
         * Invalidate TLB Entries.
         */
-       fire_write(iommu->iommu_flushinv, ~(u64)0);
+       upa_writeq(~(u64)0, iommu->iommu_flushinv);
 
        err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
                               pbm->numa_node);
        if (err)
                return err;
 
-       fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
+       upa_writeq(__pa(iommu->page_table) | 0x7UL, iommu->iommu_tsbbase);
 
-       control = fire_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control |= (0x00000400 /* TSB cache snoop enable */     |
                    0x00000300 /* Cache mode */                 |
                    0x00000002 /* Bypass enable */              |
                    0x00000001 /* Translation enable */);
-       fire_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        return 0;
 }
@@ -165,7 +147,7 @@ struct pci_msiq_entry {
 static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
                             unsigned long *head)
 {
-       *head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
+       *head = upa_readq(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
        return 0;
 }
 
@@ -191,8 +173,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
        *msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
                          MSIQ_WORD0_DATA0_SHIFT);
 
-       fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
-                  MSI_CLEAR_EQWR_N);
+       upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi_num));
 
        /* Clear the entry.  */
        ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
@@ -208,7 +189,7 @@ static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
 static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
                             unsigned long head)
 {
-       fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
+       upa_writeq(head, pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
        return 0;
 }
 
@@ -217,17 +198,16 @@ static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
 {
        u64 val;
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        val &= ~(MSI_MAP_EQNUM);
        val |= msiqid;
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
-       fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
-                  MSI_CLEAR_EQWR_N);
+       upa_writeq(MSI_CLEAR_EQWR_N, pbm->pbm_regs + MSI_CLEAR(msi));
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        val |= MSI_MAP_VALID;
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
        return 0;
 }
@@ -237,12 +217,12 @@ static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
        unsigned long msiqid;
        u64 val;
 
-       val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
+       val = upa_readq(pbm->pbm_regs + MSI_MAP(msi));
        msiqid = (val & MSI_MAP_EQNUM);
 
        val &= ~MSI_MAP_VALID;
 
-       fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
+       upa_writeq(val, pbm->pbm_regs + MSI_MAP(msi));
 
        return 0;
 }
@@ -261,22 +241,19 @@ static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
        memset((char *)pages, 0, PAGE_SIZE << order);
        pbm->msi_queues = (void *) pages;
 
-       fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
-                  (EVENT_QUEUE_BASE_ADDR_ALL_ONES |
-                   __pa(pbm->msi_queues)));
+       upa_writeq((EVENT_QUEUE_BASE_ADDR_ALL_ONES |
+                   __pa(pbm->msi_queues)),
+                  pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG);
 
-       fire_write(pbm->pbm_regs + IMONDO_DATA0,
-                  pbm->portid << 6);
-       fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
+       upa_writeq(pbm->portid << 6, pbm->pbm_regs + IMONDO_DATA0);
+       upa_writeq(0, pbm->pbm_regs + IMONDO_DATA1);
 
-       fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
-                  pbm->msi32_start);
-       fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
-                  pbm->msi64_start);
+       upa_writeq(pbm->msi32_start, pbm->pbm_regs + MSI_32BIT_ADDR);
+       upa_writeq(pbm->msi64_start, pbm->pbm_regs + MSI_64BIT_ADDR);
 
        for (i = 0; i < pbm->msiq_num; i++) {
-               fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
-               fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
+               upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_HEAD(i));
+               upa_writeq(0, pbm->pbm_regs + EVENT_QUEUE_TAIL(i));
        }
 
        return 0;
@@ -310,9 +287,9 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
        /* XXX iterate amongst the 4 IRQ controllers XXX */
        int_ctrlr = (1UL << 6);
 
-       val = fire_read(imap_reg);
+       val = upa_readq(imap_reg);
        val |= (1UL << 63) | int_ctrlr;
-       fire_write(imap_reg, val);
+       upa_writeq(val, imap_reg);
 
        fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
 
@@ -320,9 +297,8 @@ static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
        if (!virt_irq)
                return -ENOMEM;
 
-       fire_write(pbm->pbm_regs +
-                  EVENT_QUEUE_CONTROL_SET(msiqid),
-                  EVENT_QUEUE_CONTROL_SET_EN);
+       upa_writeq(EVENT_QUEUE_CONTROL_SET_EN,
+                  pbm->pbm_regs + EVENT_QUEUE_CONTROL_SET(msiqid));
 
        return virt_irq;
 }
@@ -390,77 +366,65 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
 {
        u64 val;
 
-       fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
-                  FIRE_PARITY_ENAB);
+       upa_writeq(FIRE_PARITY_ENAB,
+                  pbm->controller_regs + FIRE_PARITY_CONTROL);
 
-       fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
-                  (FIRE_FATAL_RESET_SPARE |
+       upa_writeq((FIRE_FATAL_RESET_SPARE |
                    FIRE_FATAL_RESET_MB |
                    FIRE_FATAL_RESET_CPE |
                    FIRE_FATAL_RESET_APE |
                    FIRE_FATAL_RESET_PIO |
                    FIRE_FATAL_RESET_JW |
                    FIRE_FATAL_RESET_JI |
-                   FIRE_FATAL_RESET_JR));
+                   FIRE_FATAL_RESET_JR),
+                  pbm->controller_regs + FIRE_FATAL_RESET_CTL);
 
-       fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
+       upa_writeq(~(u64)0, pbm->controller_regs + FIRE_CORE_INTR_ENABLE);
 
-       val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
+       val = upa_readq(pbm->pbm_regs + FIRE_TLU_CTRL);
        val |= (FIRE_TLU_CTRL_TIM |
                FIRE_TLU_CTRL_QDET |
                FIRE_TLU_CTRL_CFG);
-       fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
-       fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
-       fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
-                  FIRE_TLU_LINK_CTRL_CLK);
-
-       fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
-                  FIRE_LPU_LLCFG_VC0);
-       fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
-                  (FIRE_LPU_FCTRL_UCTRL_N |
-                   FIRE_LPU_FCTRL_UCTRL_P));
-       fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
-                  ((0xffff << 16) | (0x0000 << 0)));
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
-                  (2 << 16) | (140 << 8));
-       fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
-
-       fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
-       fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
-       fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
-
-       fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
+       upa_writeq(val, pbm->pbm_regs + FIRE_TLU_CTRL);
+       upa_writeq(0, pbm->pbm_regs + FIRE_TLU_DEV_CTRL);
+       upa_writeq(FIRE_TLU_LINK_CTRL_CLK,
+                  pbm->pbm_regs + FIRE_TLU_LINK_CTRL);
+
+       upa_writeq(0, pbm->pbm_regs + FIRE_LPU_RESET);
+       upa_writeq(FIRE_LPU_LLCFG_VC0, pbm->pbm_regs + FIRE_LPU_LLCFG);
+       upa_writeq((FIRE_LPU_FCTRL_UCTRL_N | FIRE_LPU_FCTRL_UCTRL_P),
+                  pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL);
+       upa_writeq(((0xffff << 16) | (0x0000 << 0)),
+                  pbm->pbm_regs + FIRE_LPU_TXL_FIFOP);
+       upa_writeq(3000000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2);
+       upa_writeq(500000, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3);
+       upa_writeq((2 << 16) | (140 << 8),
+                  pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4);
+       upa_writeq(0, pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5);
+
+       upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_DMC_IENAB);
+       upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_A);
+       upa_writeq(0, pbm->pbm_regs + FIRE_DMC_DBG_SEL_B);
+
+       upa_writeq(~(u64)0, pbm->pbm_regs + FIRE_PEC_IENAB);
 }
 
-static int __init pci_fire_pbm_init(struct pci_controller_info *p,
-                                   struct device_node *dp, u32 portid)
+static int __init pci_fire_pbm_init(struct pci_pbm_info *pbm,
+                                   struct of_device *op, u32 portid)
 {
        const struct linux_prom64_registers *regs;
-       struct pci_pbm_info *pbm;
+       struct device_node *dp = op->node;
        int err;
 
-       if ((portid & 1) == 0)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
        pbm->numa_node = -1;
 
-       pbm->scan_bus = pci_fire_scan_bus;
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 12;
 
        pbm->index = pci_num_pbms++;
 
        pbm->portid = portid;
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
        pbm->name = dp->full_name;
 
        regs = of_get_property(dp, "reg", NULL);
@@ -481,53 +445,77 @@ static int __init pci_fire_pbm_init(struct pci_controller_info *p,
 
        pci_fire_msi_init(pbm);
 
-       return 0;
-}
+       pbm->pci_bus = pci_scan_one_pbm(pbm, &op->dev);
+
+       /* XXX register error interrupt handlers XXX */
+
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
 
-static inline int portid_compare(u32 x, u32 y)
-{
-       if (x == (y ^ 1))
-               return 1;
        return 0;
 }
 
-void __init fire_pci_init(struct device_node *dp, const char *model_name)
+static int __devinit fire_probe(struct of_device *op,
+                               const struct of_device_id *match)
 {
-       struct pci_controller_info *p;
-       u32 portid = of_getintprop_default(dp, "portid", 0xff);
-       struct iommu *iommu;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
+       struct iommu *iommu;
+       u32 portid;
+       int err;
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (portid_compare(pbm->portid, portid)) {
-                       if (pci_fire_pbm_init(pbm->parent, dp, portid))
-                               goto fatal_memory_error;
-                       return;
-               }
+       portid = of_getintprop_default(dp, "portid", 0xff);
+
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbminfo.\n");
+               goto out_err;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+               goto out_free_controller;
+       }
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       p->pbm_A.iommu = iommu;
+       err = pci_fire_pbm_init(pbm, op, portid);
+       if (err)
+               goto out_free_iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       dev_set_drvdata(&op->dev, pbm);
 
-       p->pbm_B.iommu = iommu;
+       return 0;
 
-       if (pci_fire_pbm_init(p, dp, portid))
-               goto fatal_memory_error;
+out_free_iommu:
+       kfree(pbm->iommu);
+                       
+out_free_controller:
+       kfree(pbm);
 
-       return;
+out_err:
+       return err;
+}
+
+static struct of_device_id __initdata fire_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pciex108e,80f0",
+       },
+       {},
+};
 
-fatal_memory_error:
-       prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
-       prom_halt();
+static struct of_platform_driver fire_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = fire_match,
+       .probe          = fire_probe,
+};
+
+static int __init fire_init(void)
+{
+       return of_register_driver(&fire_driver, &of_bus_type);
 }
+
+subsys_initcall(fire_init);
index c385d126be1185240f3613e60cdf30f0d6365351..03186824327ebc5f66d6a060704dff3e1becda23 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/msi.h>
+#include <linux/of_device.h>
 #include <asm/io.h>
 #include <asm/prom.h>
 #include <asm/iommu.h>
@@ -56,15 +57,11 @@ struct sparc64_msiq_cookie {
 };
 #endif
 
-struct pci_controller_info;
-
 struct pci_pbm_info {
        struct pci_pbm_info             *next;
+       struct pci_pbm_info             *sibling;
        int                             index;
 
-       /* PCI controller we sit under. */
-       struct pci_controller_info      *parent;
-
        /* Physical address base of controller registers. */
        unsigned long                   controller_regs;
 
@@ -94,7 +91,7 @@ struct pci_pbm_info {
        char                            *name;
 
        /* OBP specific information. */
-       struct device_node              *prom_node;
+       struct of_device                *op;
        u64                             ino_bitmap;
 
        /* PBM I/O and Memory space resources. */
@@ -107,6 +104,10 @@ struct pci_pbm_info {
        /* This will be 12 on PCI-E controllers, 8 elsewhere.  */
        unsigned long                   config_space_reg_bits;
 
+       unsigned long                   pci_afsr;
+       unsigned long                   pci_afar;
+       unsigned long                   pci_csr;
+
        /* State of 66MHz capabilities on this PBM. */
        int                             is_66mhz_capable;
        int                             all_devs_66mhz;
@@ -146,25 +147,19 @@ struct pci_pbm_info {
        unsigned int                    pci_first_busno;
        unsigned int                    pci_last_busno;
        struct pci_bus                  *pci_bus;
-       void (*scan_bus)(struct pci_pbm_info *);
        struct pci_ops                  *pci_ops;
 
        int                             numa_node;
 };
 
-struct pci_controller_info {
-       /* The PCI bus modules controlled by us. */
-       struct pci_pbm_info             pbm_A;
-       struct pci_pbm_info             pbm_B;
-};
-
 extern struct pci_pbm_info *pci_pbm_root;
 
 extern int pci_num_pbms;
 
 /* PCI bus scanning and fixup support. */
 extern void pci_get_pbm_props(struct pci_pbm_info *pbm);
-extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
+extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
+                                       struct device *parent);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
 /* Error reporting support. */
@@ -183,4 +178,8 @@ extern void pci_config_write32(u32 *addr, u32 val);
 extern struct pci_ops sun4u_pci_ops;
 extern struct pci_ops sun4v_pci_ops;
 
+extern volatile int pci_poke_in_progress;
+extern volatile int pci_poke_cpu;
+extern volatile int pci_poke_faulted;
+
 #endif /* !(PCI_IMPL_H) */
index 60c71e35021253fde9a38501e3e61b5de0b9f0d8..2e680f34f727fa61f5defef92e63b8144e365d70 100644 (file)
@@ -323,7 +323,7 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
        const u32 *val;
        int len;
 
-       val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
+       val = of_get_property(pbm->op->node, "#msi-eqs", &len);
        if (!val || len != 4)
                goto no_msi;
        pbm->msiq_num = *val;
@@ -346,16 +346,16 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                        u32 msi64_len;
                } *arng;
 
-               val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
+               val = of_get_property(pbm->op->node, "msi-eq-size", &len);
                if (!val || len != 4)
                        goto no_msi;
 
                pbm->msiq_ent_count = *val;
 
-               mqp = of_get_property(pbm->prom_node,
+               mqp = of_get_property(pbm->op->node,
                                      "msi-eq-to-devino", &len);
                if (!mqp)
-                       mqp = of_get_property(pbm->prom_node,
+                       mqp = of_get_property(pbm->op->node,
                                              "msi-eq-devino", &len);
                if (!mqp || len != sizeof(struct msiq_prop))
                        goto no_msi;
@@ -363,27 +363,27 @@ void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
                pbm->msiq_first = mqp->first_msiq;
                pbm->msiq_first_devino = mqp->first_devino;
 
-               val = of_get_property(pbm->prom_node, "#msi", &len);
+               val = of_get_property(pbm->op->node, "#msi", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_num = *val;
 
-               mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
+               mrng = of_get_property(pbm->op->node, "msi-ranges", &len);
                if (!mrng || len != sizeof(struct msi_range_prop))
                        goto no_msi;
                pbm->msi_first = mrng->first_msi;
 
-               val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
+               val = of_get_property(pbm->op->node, "msi-data-mask", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msi_data_mask = *val;
 
-               val = of_get_property(pbm->prom_node, "msix-data-width", &len);
+               val = of_get_property(pbm->op->node, "msix-data-width", &len);
                if (!val || len != 4)
                        goto no_msi;
                pbm->msix_data_width = *val;
 
-               arng = of_get_property(pbm->prom_node, "msi-address-ranges",
+               arng = of_get_property(pbm->op->node, "msi-address-ranges",
                                       &len);
                if (!arng || len != sizeof(struct addr_range_prop))
                        goto no_msi;
index f85b6bebb0be1c7548366e982270ed4e85c3a320..dfb3ec892987ec8cca3900693d76f1df3ed2b234 100644 (file)
 #include <asm/irq.h>
 #include <asm/starfire.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All PSYCHO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define psycho_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define psycho_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "psycho"
+#define PFX            DRIVER_NAME ": "
 
 /* Misc. PSYCHO PCI controller register offsets and definitions. */
 #define PSYCHO_CONTROL         0x0010UL
 #define  PSYCHO_PCICTRL_RESV4   0x00000000000000c0UL /* Reserved                     */
 #define  PSYCHO_PCICTRL_AEN     0x000000000000003fUL /* PCI DVMA Arbitration Enable  */
 
-/* U2P Programmer's Manual, page 13-55, configuration space
- * address format:
- * 
- *  32             24 23 16 15    11 10       8 7   2  1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define PSYCHO_CONFIG_BASE(PBM)        \
-       ((PBM)->config_space | (1UL << 24))
-#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)  \
-       (((unsigned long)(BUS)   << 16) |       \
-        ((unsigned long)(DEVFN) << 8)  |       \
-        ((unsigned long)(REG)))
-
-static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
-                                     unsigned char bus,
-                                     unsigned int devfn,
-                                     int where)
-{
-       if (!pbm)
-               return NULL;
-       return (void *)
-               (PSYCHO_CONFIG_BASE(pbm) |
-                PSYCHO_CONFIG_ENCODE(bus, devfn, where));
-}
-
 /* PSYCHO error handling support. */
-enum psycho_error_type {
-       UE_ERR, CE_ERR, PCI_ERR
-};
 
 /* Helper function of IOMMU error checking, which checks out
  * the state of the streaming buffers.  The IOMMU lock is
@@ -122,129 +77,10 @@ enum psycho_error_type {
 #define PSYCHO_STC_DATA_B      0xc000UL
 #define PSYCHO_STC_ERR_A       0xb400UL
 #define PSYCHO_STC_ERR_B       0xc400UL
-#define  PSYCHO_STCERR_WRITE    0x0000000000000002UL   /* Write Error */
-#define  PSYCHO_STCERR_READ     0x0000000000000001UL   /* Read Error */
 #define PSYCHO_STC_TAG_A       0xb800UL
 #define PSYCHO_STC_TAG_B       0xc800UL
-#define  PSYCHO_STCTAG_PPN      0x0fffffff00000000UL   /* Physical Page Number */
-#define  PSYCHO_STCTAG_VPN      0x00000000ffffe000UL   /* Virtual Page Number */
-#define  PSYCHO_STCTAG_VALID    0x0000000000000002UL   /* Valid */
-#define  PSYCHO_STCTAG_WRITE    0x0000000000000001UL   /* Writable */
 #define PSYCHO_STC_LINE_A      0xb900UL
 #define PSYCHO_STC_LINE_B      0xc900UL
-#define  PSYCHO_STCLINE_LINDX   0x0000000001e00000UL   /* LRU Index */
-#define  PSYCHO_STCLINE_SPTR    0x00000000001f8000UL   /* Dirty Data Start Pointer */
-#define  PSYCHO_STCLINE_LADDR   0x0000000000007f00UL   /* Line Address */
-#define  PSYCHO_STCLINE_EPTR    0x00000000000000fcUL   /* Dirty Data End Pointer */
-#define  PSYCHO_STCLINE_VALID   0x0000000000000002UL   /* Valid */
-#define  PSYCHO_STCLINE_FOFN    0x0000000000000001UL   /* Fetch Outstanding / Flush Necessary */
-
-static DEFINE_SPINLOCK(stc_buf_lock);
-static unsigned long stc_error_buf[128];
-static unsigned long stc_tag_buf[16];
-static unsigned long stc_line_buf[16];
-
-static void __psycho_check_one_stc(struct pci_pbm_info *pbm,
-                                  int is_pbm_a)
-{
-       struct strbuf *strbuf = &pbm->stc;
-       unsigned long regbase = pbm->controller_regs;
-       unsigned long err_base, tag_base, line_base;
-       u64 control;
-       int i;
-
-       if (is_pbm_a) {
-               err_base = regbase + PSYCHO_STC_ERR_A;
-               tag_base = regbase + PSYCHO_STC_TAG_A;
-               line_base = regbase + PSYCHO_STC_LINE_A;
-       } else {
-               err_base = regbase + PSYCHO_STC_ERR_B;
-               tag_base = regbase + PSYCHO_STC_TAG_B;
-               line_base = regbase + PSYCHO_STC_LINE_B;
-       }
-
-       spin_lock(&stc_buf_lock);
-
-       /* This is __REALLY__ dangerous.  When we put the
-        * streaming buffer into diagnostic mode to probe
-        * it's tags and error status, we _must_ clear all
-        * of the line tag valid bits before re-enabling
-        * the streaming buffer.  If any dirty data lives
-        * in the STC when we do this, we will end up
-        * invalidating it before it has a chance to reach
-        * main memory.
-        */
-       control = psycho_read(strbuf->strbuf_control);
-       psycho_write(strbuf->strbuf_control,
-                    (control | PSYCHO_STRBUF_CTRL_DENAB));
-       for (i = 0; i < 128; i++) {
-               unsigned long val;
-
-               val = psycho_read(err_base + (i * 8UL));
-               psycho_write(err_base + (i * 8UL), 0UL);
-               stc_error_buf[i] = val;
-       }
-       for (i = 0; i < 16; i++) {
-               stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL));
-               stc_line_buf[i] = psycho_read(line_base + (i * 8UL));
-               psycho_write(tag_base + (i * 8UL), 0UL);
-               psycho_write(line_base + (i * 8UL), 0UL);
-       }
-
-       /* OK, state is logged, exit diagnostic mode. */
-       psycho_write(strbuf->strbuf_control, control);
-
-       for (i = 0; i < 16; i++) {
-               int j, saw_error, first, last;
-
-               saw_error = 0;
-               first = i * 8;
-               last = first + 8;
-               for (j = first; j < last; j++) {
-                       unsigned long errval = stc_error_buf[j];
-                       if (errval != 0) {
-                               saw_error++;
-                               printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n",
-                                      pbm->name,
-                                      j,
-                                      (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
-                                      (errval & PSYCHO_STCERR_READ) ? 1 : 0);
-                       }
-               }
-               if (saw_error != 0) {
-                       unsigned long tagval = stc_tag_buf[i];
-                       unsigned long lineval = stc_line_buf[i];
-                       printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n",
-                              pbm->name,
-                              i,
-                              ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
-                              (tagval & PSYCHO_STCTAG_VPN),
-                              ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
-                              ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
-                       printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)"
-                              "V(%d)FOFN(%d)]\n",
-                              pbm->name,
-                              i,
-                              ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
-                              ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
-                              ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
-                              ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
-                              ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
-                              ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
-               }
-       }
-
-       spin_unlock(&stc_buf_lock);
-}
-
-static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
-                                    unsigned long afsr,
-                                    unsigned long afar,
-                                    enum psycho_error_type type)
-{
-       __psycho_check_one_stc(pbm,
-                              (pbm == &pbm->parent->pbm_A));
-}
 
 /* When an Uncorrectable Error or a PCI Error happens, we
  * interrogate the IOMMU state to see if it is the cause.
@@ -271,122 +107,7 @@ static void __psycho_check_stc_error(struct pci_pbm_info *pbm,
 #define PSYCHO_IOMMU_TSBBASE   0x0208UL
 #define PSYCHO_IOMMU_FLUSH     0x0210UL
 #define PSYCHO_IOMMU_TAG       0xa580UL
-#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
-#define  PSYCHO_IOMMU_TAG_ERR   (0x1UL << 22UL)
-#define  PSYCHO_IOMMU_TAG_WRITE         (0x1UL << 21UL)
-#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
-#define  PSYCHO_IOMMU_TAG_SIZE  (0x1UL << 19UL)
-#define  PSYCHO_IOMMU_TAG_VPAGE         0x7ffffUL
 #define PSYCHO_IOMMU_DATA      0xa600UL
-#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
-#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
-#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
-static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
-                                    unsigned long afsr,
-                                    unsigned long afar,
-                                    enum psycho_error_type type)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long iommu_tag[16];
-       unsigned long iommu_data[16];
-       unsigned long flags;
-       u64 control;
-       int i;
-
-       spin_lock_irqsave(&iommu->lock, flags);
-       control = psycho_read(iommu->iommu_control);
-       if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
-               char *type_string;
-
-               /* Clear the error encountered bit. */
-               control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
-               psycho_write(iommu->iommu_control, control);
-
-               switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
-               case 0:
-                       type_string = "Protection Error";
-                       break;
-               case 1:
-                       type_string = "Invalid Error";
-                       break;
-               case 2:
-                       type_string = "TimeOut Error";
-                       break;
-               case 3:
-               default:
-                       type_string = "ECC Error";
-                       break;
-               };
-               printk("%s: IOMMU Error, type[%s]\n",
-                      pbm->name, type_string);
-
-               /* Put the IOMMU into diagnostic mode and probe
-                * it's TLB for entries with error status.
-                *
-                * It is very possible for another DVMA to occur
-                * while we do this probe, and corrupt the system
-                * further.  But we are so screwed at this point
-                * that we are likely to crash hard anyways, so
-                * get as much diagnostic information to the
-                * console as we can.
-                */
-               psycho_write(iommu->iommu_control,
-                            control | PSYCHO_IOMMU_CTRL_DENAB);
-               for (i = 0; i < 16; i++) {
-                       unsigned long base = pbm->controller_regs;
-
-                       iommu_tag[i] =
-                               psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL));
-                       iommu_data[i] =
-                               psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL));
-
-                       /* Now clear out the entry. */
-                       psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-                       psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-               }
-
-               /* Leave diagnostic mode. */
-               psycho_write(iommu->iommu_control, control);
-
-               for (i = 0; i < 16; i++) {
-                       unsigned long tag, data;
-
-                       tag = iommu_tag[i];
-                       if (!(tag & PSYCHO_IOMMU_TAG_ERR))
-                               continue;
-
-                       data = iommu_data[i];
-                       switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
-                       case 0:
-                               type_string = "Protection Error";
-                               break;
-                       case 1:
-                               type_string = "Invalid Error";
-                               break;
-                       case 2:
-                               type_string = "TimeOut Error";
-                               break;
-                       case 3:
-                       default:
-                               type_string = "ECC Error";
-                               break;
-                       };
-                       printk("%s: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n",
-                              pbm->name, i, type_string,
-                              ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
-                              ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
-                              ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
-                              (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
-                       printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
-                              pbm->name, i,
-                              ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
-                              ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
-                              (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
-               }
-       }
-       __psycho_check_stc_error(pbm, afsr, afar, type);
-       spin_unlock_irqrestore(&iommu->lock, flags);
-}
 
 /* Uncorrectable Errors.  Cause of the error and the address are
  * recorded in the UE_AFSR and UE_AFAR of PSYCHO.  They are errors
@@ -410,15 +131,14 @@ static void psycho_check_iommu_error(struct pci_pbm_info *pbm,
 static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR;
        unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported;
 
        /* Latch uncorrectable error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear the primary/secondary error status bits. */
        error_bits = afsr &
@@ -426,7 +146,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
                 PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       psycho_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -463,8 +183,9 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate both IOMMUs for error status. */
-       psycho_check_iommu_error(&p->pbm_A, afsr, afar, UE_ERR);
-       psycho_check_iommu_error(&p->pbm_B, afsr, afar, UE_ERR);
+       psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
+       if (pbm->sibling)
+               psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -495,8 +216,8 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -504,7 +225,7 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
                 PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       psycho_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -554,164 +275,9 @@ static irqreturn_t psycho_ce_intr(int irq, void *dev_id)
  */
 #define PSYCHO_PCI_AFSR_A      0x2010UL
 #define PSYCHO_PCI_AFSR_B      0x4010UL
-#define  PSYCHO_PCIAFSR_PMA    0x8000000000000000UL /* Primary Master Abort Error   */
-#define  PSYCHO_PCIAFSR_PTA    0x4000000000000000UL /* Primary Target Abort Error   */
-#define  PSYCHO_PCIAFSR_PRTRY  0x2000000000000000UL /* Primary Excessive Retries    */
-#define  PSYCHO_PCIAFSR_PPERR  0x1000000000000000UL /* Primary Parity Error         */
-#define  PSYCHO_PCIAFSR_SMA    0x0800000000000000UL /* Secondary Master Abort Error */
-#define  PSYCHO_PCIAFSR_STA    0x0400000000000000UL /* Secondary Target Abort Error */
-#define  PSYCHO_PCIAFSR_SRTRY  0x0200000000000000UL /* Secondary Excessive Retries  */
-#define  PSYCHO_PCIAFSR_SPERR  0x0100000000000000UL /* Secondary Parity Error       */
-#define  PSYCHO_PCIAFSR_RESV1  0x00ff000000000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_BMSK   0x0000ffff00000000UL /* Bytemask of failed transfer  */
-#define  PSYCHO_PCIAFSR_BLK    0x0000000080000000UL /* Trans was block operation    */
-#define  PSYCHO_PCIAFSR_RESV2  0x0000000040000000UL /* Reserved                     */
-#define  PSYCHO_PCIAFSR_MID    0x000000003e000000UL /* MID causing the error        */
-#define  PSYCHO_PCIAFSR_RESV3  0x0000000001ffffffUL /* Reserved                     */
 #define PSYCHO_PCI_AFAR_A      0x2018UL
 #define PSYCHO_PCI_AFAR_B      0x4018UL
 
-static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a)
-{
-       unsigned long csr_reg, csr, csr_error_bits;
-       irqreturn_t ret = IRQ_NONE;
-       u16 stat, *addr;
-
-       if (is_pbm_a) {
-               csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL;
-       } else {
-               csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL;
-       }
-       csr = psycho_read(csr_reg);
-       csr_error_bits =
-               csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
-       if (csr_error_bits) {
-               /* Clear the errors.  */
-               psycho_write(csr_reg, csr);
-
-               /* Log 'em.  */
-               if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
-                       printk("%s: PCI streaming byte hole error asserted.\n",
-                              pbm->name);
-               if (csr_error_bits & PSYCHO_PCICTRL_SERR)
-                       printk("%s: PCI SERR signal asserted.\n", pbm->name);
-               ret = IRQ_HANDLED;
-       }
-       addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
-                                       0, PCI_STATUS);
-       pci_config_read16(addr, &stat);
-       if (stat & (PCI_STATUS_PARITY |
-                   PCI_STATUS_SIG_TARGET_ABORT |
-                   PCI_STATUS_REC_TARGET_ABORT |
-                   PCI_STATUS_REC_MASTER_ABORT |
-                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
-               printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-                      pbm->name, stat);
-               pci_config_write16(addr, 0xffff);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
-{
-       struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
-       unsigned long afsr_reg, afar_reg;
-       unsigned long afsr, afar, error_bits;
-       int is_pbm_a, reported;
-
-       is_pbm_a = (pbm == &pbm->parent->pbm_A);
-       if (is_pbm_a) {
-               afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A;
-               afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A;
-       } else {
-               afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B;
-               afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_B;
-       }
-
-       /* Latch error status. */
-       afar = psycho_read(afar_reg);
-       afsr = psycho_read(afsr_reg);
-
-       /* Clear primary/secondary error status bits. */
-       error_bits = afsr &
-               (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
-                PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
-                PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
-                PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
-       if (!error_bits)
-               return psycho_pcierr_intr_other(pbm, is_pbm_a);
-       psycho_write(afsr_reg, error_bits);
-
-       /* Log the error. */
-       printk("%s: PCI Error, primary error type[%s]\n",
-              pbm->name,
-              (((error_bits & PSYCHO_PCIAFSR_PMA) ?
-                "Master Abort" :
-                ((error_bits & PSYCHO_PCIAFSR_PTA) ?
-                 "Target Abort" :
-                 ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
-                  "Excessive Retries" :
-                  ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
-                   "Parity Error" : "???"))))));
-       printk("%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
-              pbm->name,
-              (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
-              (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
-              (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
-       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-       printk("%s: PCI Secondary errors [", pbm->name);
-       reported = 0;
-       if (afsr & PSYCHO_PCIAFSR_SMA) {
-               reported++;
-               printk("(Master Abort)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_STA) {
-               reported++;
-               printk("(Target Abort)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_SRTRY) {
-               reported++;
-               printk("(Excessive Retries)");
-       }
-       if (afsr & PSYCHO_PCIAFSR_SPERR) {
-               reported++;
-               printk("(Parity Error)");
-       }
-       if (!reported)
-               printk("(none)");
-       printk("]\n");
-
-       /* For the error types shown, scan PBM's PCI bus for devices
-        * which have logged that error type.
-        */
-
-       /* If we see a Target Abort, this could be the result of an
-        * IOMMU translation error of some sort.  It is extremely
-        * useful to log this information as usually it indicates
-        * a bug in the IOMMU support code or a PCI device driver.
-        */
-       if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
-               psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
-               pci_scan_for_target_abort(pbm, pbm->pci_bus);
-       }
-       if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
-               pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-       /* For excessive retries, PSYCHO/PBM will abort the device
-        * and there is no way to specifically check for excessive
-        * retries in the config space status registers.  So what
-        * we hope is that we'll catch it via the master/target
-        * abort events.
-        */
-
-       if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
-               pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-       return IRQ_HANDLED;
-}
-
 /* XXX What about PowerFail/PowerManagement??? -DaveM */
 #define PSYCHO_ECC_CTRL                0x0020
 #define  PSYCHO_ECCCTRL_EE      0x8000000000000000UL /* Enable ECC Checking */
@@ -719,7 +285,7 @@ static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
 #define  PSYCHO_ECCCTRL_CE      0x2000000000000000UL /* Enable CE INterrupts */
 static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        unsigned long base = pbm->controller_regs;
        u64 tmp;
        int err;
@@ -762,27 +328,26 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm)
                       "err=%d\n", pbm->name, err);
 
        /* Enable UE and CE interrupts for controller. */
-       psycho_write(base + PSYCHO_ECC_CTRL,
-                    (PSYCHO_ECCCTRL_EE |
-                     PSYCHO_ECCCTRL_UE |
-                     PSYCHO_ECCCTRL_CE));
+       upa_writeq((PSYCHO_ECCCTRL_EE |
+                   PSYCHO_ECCCTRL_UE |
+                   PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL);
 
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = psycho_read(base + PSYCHO_PCIA_CTRL);
+       tmp = upa_readq(base + PSYCHO_PCIA_CTRL);
        tmp |= (PSYCHO_PCICTRL_SERR |
                PSYCHO_PCICTRL_SBH_ERR |
                PSYCHO_PCICTRL_EEN);
        tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-       psycho_write(base + PSYCHO_PCIA_CTRL, tmp);
+       upa_writeq(tmp, base + PSYCHO_PCIA_CTRL);
                     
-       tmp = psycho_read(base + PSYCHO_PCIB_CTRL);
+       tmp = upa_readq(base + PSYCHO_PCIB_CTRL);
        tmp |= (PSYCHO_PCICTRL_SERR |
                PSYCHO_PCICTRL_SBH_ERR |
                PSYCHO_PCICTRL_EEN);
        tmp &= ~(PSYCHO_PCICTRL_SBH_INT);
-       psycho_write(base + PSYCHO_PCIB_CTRL, tmp);
+       upa_writeq(tmp, base + PSYCHO_PCIB_CTRL);
 }
 
 /* PSYCHO boot time probing and initialization. */
@@ -803,11 +368,12 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
+static void __init psycho_scan_bus(struct pci_pbm_info *pbm,
+                                  struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable = 0;
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        /* After the PCI bus scan is complete, we can register
         * the error interrupt handlers.
@@ -815,61 +381,6 @@ static void __init psycho_scan_bus(struct pci_pbm_info *pbm)
        psycho_register_error_handlers(pbm);
 }
 
-static int psycho_iommu_init(struct pci_pbm_info *pbm)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-
-       /* PSYCHO's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-
-       /* We use the main control register of PSYCHO as the write
-        * completion register.
-        */
-       iommu->write_complete_reg = pbm->controller_regs + PSYCHO_CONTROL;
-
-       /*
-        * Invalidate TLB Entries.
-        */
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control |= PSYCHO_IOMMU_CTRL_DENAB;
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-       for(i = 0; i < 16; i++) {
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TAG + (i * 8UL), 0);
-               psycho_write(pbm->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff,
-                              pbm->numa_node);
-       if (err)
-               return err;
-
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
-                    __pa(iommu->page_table));
-
-       control = psycho_read(pbm->controller_regs + PSYCHO_IOMMU_CONTROL);
-       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
-       control |= (PSYCHO_IOMMU_TSBSZ_128K | PSYCHO_IOMMU_CTRL_ENAB);
-       psycho_write(pbm->controller_regs + PSYCHO_IOMMU_CONTROL, control);
-
-       /* If necessary, hook us up for starfire IRQ translations. */
-       if (this_is_starfire)
-               starfire_hookup(pbm->portid);
-
-       return 0;
-}
-
 #define PSYCHO_IRQ_RETRY       0x1a00UL
 #define PSYCHO_PCIA_DIAG       0x2020UL
 #define PSYCHO_PCIB_DIAG       0x4020UL
@@ -886,28 +397,28 @@ static void psycho_controller_hwinit(struct pci_pbm_info *pbm)
 {
        u64 tmp;
 
-       psycho_write(pbm->controller_regs + PSYCHO_IRQ_RETRY, 5);
+       upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY);
 
        /* Enable arbiter for all PCI slots. */
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_CTRL);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIA_CTRL, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL);
 
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_CTRL);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL);
        tmp |= PSYCHO_PCICTRL_AEN;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIB_CTRL, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL);
 
        /* Disable DMA write / PIO read synchronization on
         * both PCI bus segments.
         * [ U2P Erratum 1243770, STP2223BGA data sheet ]
         */
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIA_DIAG);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIA_DIAG, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG);
 
-       tmp = psycho_read(pbm->controller_regs + PSYCHO_PCIB_DIAG);
+       tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG);
        tmp |= PSYCHO_PCIDIAG_DDWSYNC;
-       psycho_write(pbm->controller_regs + PSYCHO_PCIB_DIAG, tmp);
+       upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG);
 }
 
 static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
@@ -920,10 +431,16 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
                pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_A;
                pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_A;
                pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_A;
+               pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A;
+               pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A;
+               pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A;
        } else {
                pbm->stc.strbuf_control  = base + PSYCHO_STRBUF_CONTROL_B;
                pbm->stc.strbuf_pflush   = base + PSYCHO_STRBUF_FLUSH_B;
                pbm->stc.strbuf_fsync    = base + PSYCHO_STRBUF_FSYNC_B;
+               pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B;
+               pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B;
+               pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B;
        }
        /* PSYCHO's streaming buffer lacks ctx flushing. */
        pbm->stc.strbuf_ctxflush      = 0;
@@ -946,7 +463,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
         */
 #undef PSYCHO_STRBUF_RERUN_ENABLE
 #undef PSYCHO_STRBUF_RERUN_DISABLE
-       control = psycho_read(pbm->stc.strbuf_control);
+       control = upa_readq(pbm->stc.strbuf_control);
        control |= PSYCHO_STRBUF_CTRL_ENAB;
        control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR);
 #ifdef PSYCHO_STRBUF_RERUN_ENABLE
@@ -956,7 +473,7 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
        control |= PSYCHO_STRBUF_CTRL_RRDIS;
 #endif
 #endif
-       psycho_write(pbm->stc.strbuf_control, control);
+       upa_writeq(control, pbm->stc.strbuf_control);
 
        pbm->stc.strbuf_enabled = 1;
 }
@@ -968,111 +485,134 @@ static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm,
 #define PSYCHO_MEMSPACE_B      0x180000000UL
 #define PSYCHO_MEMSPACE_SIZE   0x07fffffffUL
 
-static void __init psycho_pbm_init(struct pci_controller_info *p,
-                           struct device_node *dp, int is_pbm_a)
+static void __init psycho_pbm_init(struct pci_pbm_info *pbm,
+                                  struct of_device *op, int is_pbm_a)
 {
-       struct property *prop;
-       struct pci_pbm_info *pbm;
-
-       if (is_pbm_a)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
-       pbm->numa_node = -1;
-
-       pbm->scan_bus = psycho_scan_bus;
-       pbm->pci_ops = &sun4u_pci_ops;
-       pbm->config_space_reg_bits = 8;
-
-       pbm->index = pci_num_pbms++;
-
-       pbm->chip_type = PBM_CHIP_TYPE_PSYCHO;
-       pbm->chip_version = 0;
-       prop = of_find_property(dp, "version#", NULL);
-       if (prop)
-               pbm->chip_version = *(int *) prop->value;
-       pbm->chip_revision = 0;
-       prop = of_find_property(dp, "module-revision#", NULL);
-       if (prop)
-               pbm->chip_revision = *(int *) prop->value;
-
-       pbm->parent = p;
-       pbm->prom_node = dp;
-       pbm->name = dp->full_name;
-
-       printk("%s: PSYCHO PCI Bus Module ver[%x:%x]\n",
-              pbm->name,
-              pbm->chip_version, pbm->chip_revision);
-
-       pci_determine_mem_io_space(pbm);
+       psycho_pbm_init_common(pbm, op, "PSYCHO", PBM_CHIP_TYPE_PSYCHO);
+       psycho_pbm_strbuf_init(pbm, is_pbm_a);
+       psycho_scan_bus(pbm, &op->dev);
+}
 
-       pci_get_pbm_props(pbm);
+static struct pci_pbm_info * __devinit psycho_find_sibling(u32 upa_portid)
+{
+       struct pci_pbm_info *pbm;
 
-       psycho_pbm_strbuf_init(pbm, is_pbm_a);
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               if (pbm->portid == upa_portid)
+                       return pbm;
+       }
+       return NULL;
 }
 
 #define PSYCHO_CONFIGSPACE     0x001000000UL
 
-void __init psycho_init(struct device_node *dp, char *model_name)
+static int __devinit psycho_probe(struct of_device *op,
+                                 const struct of_device_id *match)
 {
-       struct linux_prom64_registers *pr_regs;
-       struct pci_controller_info *p;
+       const struct linux_prom64_registers *pr_regs;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
-       struct property *prop;
+       int is_pbm_a, err;
        u32 upa_portid;
-       int is_pbm_a;
 
-       upa_portid = 0xff;
-       prop = of_find_property(dp, "upa-portid", NULL);
-       if (prop)
-               upa_portid = *(u32 *) prop->value;
+       upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               struct pci_controller_info *p = pbm->parent;
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
 
-               if (p->pbm_A.portid == upa_portid) {
-                       is_pbm_a = (p->pbm_A.prom_node == NULL);
-                       psycho_pbm_init(p, dp, is_pbm_a);
-                       return;
+       pbm->sibling = psycho_find_sibling(upa_portid);
+       if (pbm->sibling) {
+               iommu = pbm->sibling->iommu;
+       } else {
+               iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+               if (!iommu) {
+                       printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+                       goto out_free_controller;
                }
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
+       pbm->portid = upa_portid;
 
-       p->pbm_A.iommu = p->pbm_B.iommu = iommu;
+       pr_regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!pr_regs) {
+               printk(KERN_ERR PFX "No reg property.\n");
+               goto out_free_iommu;
+       }
 
-       p->pbm_A.portid = upa_portid;
-       p->pbm_B.portid = upa_portid;
+       is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
 
-       prop = of_find_property(dp, "reg", NULL);
-       pr_regs = prop->value;
+       pbm->controller_regs = pr_regs[2].phys_addr;
+       pbm->config_space = (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
 
-       p->pbm_A.controller_regs = pr_regs[2].phys_addr;
-       p->pbm_B.controller_regs = pr_regs[2].phys_addr;
+       if (is_pbm_a) {
+               pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_A;
+               pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_A;
+               pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIA_CTRL;
+       } else {
+               pbm->pci_afsr = pbm->controller_regs + PSYCHO_PCI_AFSR_B;
+               pbm->pci_afar = pbm->controller_regs + PSYCHO_PCI_AFAR_B;
+               pbm->pci_csr  = pbm->controller_regs + PSYCHO_PCIB_CTRL;
+       }
 
-       p->pbm_A.config_space = p->pbm_B.config_space =
-               (pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
+       psycho_controller_hwinit(pbm);
+       if (!pbm->sibling) {
+               err = psycho_iommu_init(pbm, 128, 0xc0000000,
+                                       0xffffffff, PSYCHO_CONTROL);
+               if (err)
+                       goto out_free_iommu;
 
-       psycho_controller_hwinit(&p->pbm_A);
+               /* If necessary, hook us up for starfire IRQ translations. */
+               if (this_is_starfire)
+                       starfire_hookup(pbm->portid);
+       }
 
-       if (psycho_iommu_init(&p->pbm_A))
-               goto fatal_memory_error;
+       psycho_pbm_init(pbm, op, is_pbm_a);
 
-       is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
-       psycho_pbm_init(p, dp, is_pbm_a);
-       return;
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       if (pbm->sibling)
+               pbm->sibling->sibling = pbm;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       if (!pbm->sibling)
+               kfree(pbm->iommu);
 
-fatal_memory_error:
-       prom_printf("PSYCHO: Fatal memory allocation error.\n");
-       prom_halt();
+out_free_controller:
+       kfree(pbm);
+
+out_err:
+       return err;
 }
+
+static struct of_device_id __initdata psycho_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,8000",
+       },
+       {},
+};
+
+static struct of_platform_driver psycho_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = psycho_match,
+       .probe          = psycho_probe,
+};
+
+static int __init psycho_init(void)
+{
+       return of_register_driver(&psycho_driver, &of_bus_type);
+}
+
+subsys_initcall(psycho_init);
index ade5184e75d132591f42139cab37a33e285bfa1a..713257b6963c0c163b8a42340e82fafb1ce5fe6a 100644 (file)
 #include <asm/apb.h>
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/oplib.h>
 #include <asm/prom.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
+#include "psycho_common.h"
 
-/* All SABRE registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define sabre_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define sabre_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "sabre"
+#define PFX            DRIVER_NAME ": "
 
 /* SABRE PCI controller register offsets and definitions. */
 #define SABRE_UE_AFSR          0x0030UL
 static int hummingbird_p;
 static struct pci_bus *sabre_root_bus;
 
-/* SABRE error handling support. */
-static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
-                                   unsigned long afsr,
-                                   unsigned long afar)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long iommu_tag[16];
-       unsigned long iommu_data[16];
-       unsigned long flags;
-       u64 control;
-       int i;
-
-       spin_lock_irqsave(&iommu->lock, flags);
-       control = sabre_read(iommu->iommu_control);
-       if (control & SABRE_IOMMUCTRL_ERR) {
-               char *type_string;
-
-               /* Clear the error encountered bit.
-                * NOTE: On Sabre this is write 1 to clear,
-                *       which is different from Psycho.
-                */
-               sabre_write(iommu->iommu_control, control);
-               switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {
-               case 1:
-                       type_string = "Invalid Error";
-                       break;
-               case 3:
-                       type_string = "ECC Error";
-                       break;
-               default:
-                       type_string = "Unknown";
-                       break;
-               };
-               printk("%s: IOMMU Error, type[%s]\n",
-                      pbm->name, type_string);
-
-               /* Enter diagnostic mode and probe for error'd
-                * entries in the IOTLB.
-                */
-               control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);
-               sabre_write(iommu->iommu_control,
-                           (control | SABRE_IOMMUCTRL_DENAB));
-               for (i = 0; i < 16; i++) {
-                       unsigned long base = pbm->controller_regs;
-
-                       iommu_tag[i] =
-                               sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));
-                       iommu_data[i] =
-                               sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));
-                       sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);
-                       sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);
-               }
-               sabre_write(iommu->iommu_control, control);
-
-               for (i = 0; i < 16; i++) {
-                       unsigned long tag, data;
-
-                       tag = iommu_tag[i];
-                       if (!(tag & SABRE_IOMMUTAG_ERR))
-                               continue;
-
-                       data = iommu_data[i];
-                       switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {
-                       case 1:
-                               type_string = "Invalid Error";
-                               break;
-                       case 3:
-                               type_string = "ECC Error";
-                               break;
-                       default:
-                               type_string = "Unknown";
-                               break;
-                       };
-                       printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",
-                              pbm->name, i, tag, type_string,
-                              ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
-                              ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
-                              ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
-                       printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
-                              pbm->name, i, data,
-                              ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
-                              ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));
-               }
-       }
-       spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
 static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
@@ -306,8 +201,8 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch uncorrectable error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear the primary/secondary error status bits. */
        error_bits = afsr &
@@ -316,7 +211,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
                 SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);
        if (!error_bits)
                return IRQ_NONE;
-       sabre_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s%s]\n",
@@ -352,7 +247,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       sabre_check_iommu_error(pbm, afsr, afar);
+       psycho_check_iommu_error(pbm, afsr, afar, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -366,8 +261,8 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        int reported;
 
        /* Latch error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -375,7 +270,7 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
                 SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);
        if (!error_bits)
                return IRQ_NONE;
-       sabre_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -413,136 +308,9 @@ static irqreturn_t sabre_ce_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm)
-{
-       unsigned long csr_reg, csr, csr_error_bits;
-       irqreturn_t ret = IRQ_NONE;
-       u16 stat;
-
-       csr_reg = pbm->controller_regs + SABRE_PCICTRL;
-       csr = sabre_read(csr_reg);
-       csr_error_bits =
-               csr & SABRE_PCICTRL_SERR;
-       if (csr_error_bits) {
-               /* Clear the errors.  */
-               sabre_write(csr_reg, csr);
-
-               /* Log 'em.  */
-               if (csr_error_bits & SABRE_PCICTRL_SERR)
-                       printk("%s: PCI SERR signal asserted.\n",
-                              pbm->name);
-               ret = IRQ_HANDLED;
-       }
-       pci_bus_read_config_word(sabre_root_bus, 0,
-                                PCI_STATUS, &stat);
-       if (stat & (PCI_STATUS_PARITY |
-                   PCI_STATUS_SIG_TARGET_ABORT |
-                   PCI_STATUS_REC_TARGET_ABORT |
-                   PCI_STATUS_REC_MASTER_ABORT |
-                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
-               printk("%s: PCI bus error, PCI_STATUS[%04x]\n",
-                      pbm->name, stat);
-               pci_bus_write_config_word(sabre_root_bus, 0,
-                                         PCI_STATUS, 0xffff);
-               ret = IRQ_HANDLED;
-       }
-       return ret;
-}
-
-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
-{
-       struct pci_pbm_info *pbm = dev_id;
-       unsigned long afsr_reg, afar_reg;
-       unsigned long afsr, afar, error_bits;
-       int reported;
-
-       afsr_reg = pbm->controller_regs + SABRE_PIOAFSR;
-       afar_reg = pbm->controller_regs + SABRE_PIOAFAR;
-
-       /* Latch error status. */
-       afar = sabre_read(afar_reg);
-       afsr = sabre_read(afsr_reg);
-
-       /* Clear primary/secondary error status bits. */
-       error_bits = afsr &
-               (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |
-                SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |
-                SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |
-                SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);
-       if (!error_bits)
-               return sabre_pcierr_intr_other(pbm);
-       sabre_write(afsr_reg, error_bits);
-
-       /* Log the error. */
-       printk("%s: PCI Error, primary error type[%s]\n",
-              pbm->name,
-              (((error_bits & SABRE_PIOAFSR_PMA) ?
-                "Master Abort" :
-                ((error_bits & SABRE_PIOAFSR_PTA) ?
-                 "Target Abort" :
-                 ((error_bits & SABRE_PIOAFSR_PRTRY) ?
-                  "Excessive Retries" :
-                  ((error_bits & SABRE_PIOAFSR_PPERR) ?
-                   "Parity Error" : "???"))))));
-       printk("%s: bytemask[%04lx] was_block(%d)\n",
-              pbm->name,
-              (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,
-              (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);
-       printk("%s: PCI AFAR [%016lx]\n", pbm->name, afar);
-       printk("%s: PCI Secondary errors [", pbm->name);
-       reported = 0;
-       if (afsr & SABRE_PIOAFSR_SMA) {
-               reported++;
-               printk("(Master Abort)");
-       }
-       if (afsr & SABRE_PIOAFSR_STA) {
-               reported++;
-               printk("(Target Abort)");
-       }
-       if (afsr & SABRE_PIOAFSR_SRTRY) {
-               reported++;
-               printk("(Excessive Retries)");
-       }
-       if (afsr & SABRE_PIOAFSR_SPERR) {
-               reported++;
-               printk("(Parity Error)");
-       }
-       if (!reported)
-               printk("(none)");
-       printk("]\n");
-
-       /* For the error types shown, scan both PCI buses for devices
-        * which have logged that error type.
-        */
-
-       /* If we see a Target Abort, this could be the result of an
-        * IOMMU translation error of some sort.  It is extremely
-        * useful to log this information as usually it indicates
-        * a bug in the IOMMU support code or a PCI device driver.
-        */
-       if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {
-               sabre_check_iommu_error(pbm, afsr, afar);
-               pci_scan_for_target_abort(pbm, pbm->pci_bus);
-       }
-       if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA))
-               pci_scan_for_master_abort(pbm, pbm->pci_bus);
-
-       /* For excessive retries, SABRE/PBM will abort the device
-        * and there is no way to specifically check for excessive
-        * retries in the config space status registers.  So what
-        * we hope is that we'll catch it via the master/target
-        * abort events.
-        */
-
-       if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR))
-               pci_scan_for_parity_error(pbm, pbm->pci_bus);
-
-       return IRQ_HANDLED;
-}
-
 static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct device_node *dp = pbm->prom_node;
+       struct device_node *dp = pbm->op->node;
        struct of_device *op;
        unsigned long base = pbm->controller_regs;
        u64 tmp;
@@ -568,33 +336,34 @@ static void sabre_register_error_handlers(struct pci_pbm_info *pbm)
         * registering the handler so that we don't get spurious
         * interrupts.
         */
-       sabre_write(base + SABRE_UE_AFSR,
-                   (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
-                    SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
-                    SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));
+       upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |
+                   SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |
+                   SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE),
+                  base + SABRE_UE_AFSR);
 
        err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n",
                       pbm->name, err);
 
-       sabre_write(base + SABRE_CE_AFSR,
-                   (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
-                    SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));
+       upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |
+                   SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR),
+                  base + SABRE_CE_AFSR);
+
 
        err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n",
                       pbm->name, err);
-       err = request_irq(op->irqs[0], sabre_pcierr_intr, 0,
+       err = request_irq(op->irqs[0], psycho_pcierr_intr, 0,
                          "SABRE_PCIERR", pbm);
        if (err)
                printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n",
                       pbm->name, err);
 
-       tmp = sabre_read(base + SABRE_PCICTRL);
+       tmp = upa_readq(base + SABRE_PCICTRL);
        tmp |= SABRE_PCICTRL_ERREN;
-       sabre_write(base + SABRE_PCICTRL, tmp);
+       upa_writeq(tmp, base + SABRE_PCICTRL);
 }
 
 static void apb_init(struct pci_bus *sabre_bus)
@@ -633,7 +402,8 @@ static void apb_init(struct pci_bus *sabre_bus)
        }
 }
 
-static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
+static void __init sabre_scan_bus(struct pci_pbm_info *pbm,
+                                 struct device *parent)
 {
        static int once;
 
@@ -656,12 +426,12 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
         * to live at bus 0.
         */
        if (once != 0) {
-               prom_printf("SABRE: Multiple controllers unsupported.\n");
-               prom_halt();
+               printk(KERN_ERR PFX "Multiple controllers unsupported.\n");
+               return;
        }
        once++;
 
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
        if (!pbm->pci_bus)
                return;
 
@@ -672,133 +442,58 @@ static void __init sabre_scan_bus(struct pci_pbm_info *pbm)
        sabre_register_error_handlers(pbm);
 }
 
-static int sabre_iommu_init(struct pci_pbm_info *pbm,
-                           int tsbsize, unsigned long dvma_offset,
-                           u32 dma_mask)
-{
-       struct iommu *iommu = pbm->iommu;
-       unsigned long i;
-       u64 control;
-       int err;
-
-       /* Register addresses. */
-       iommu->iommu_control  = pbm->controller_regs + SABRE_IOMMU_CONTROL;
-       iommu->iommu_tsbbase  = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
-       iommu->iommu_flush    = pbm->controller_regs + SABRE_IOMMU_FLUSH;
-       iommu->iommu_tags     = iommu->iommu_flush + (0xa580UL - 0x0210UL);
-       iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
-       /* Sabre's IOMMU lacks ctx flushing. */
-       iommu->iommu_ctxflush = 0;
-                                        
-       /* Invalidate TLB Entries. */
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control |= SABRE_IOMMUCTRL_DENAB;
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       for(i = 0; i < 16; i++) {
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0);
-               sabre_write(pbm->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0);
-       }
-
-       /* Leave diag mode enabled for full-flushing done
-        * in pci_iommu.c
-        */
-       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
-                              dvma_offset, dma_mask, pbm->numa_node);
-       if (err)
-               return err;
-
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
-                   __pa(iommu->page_table));
-
-       control = sabre_read(pbm->controller_regs + SABRE_IOMMU_CONTROL);
-       control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ);
-       control |= SABRE_IOMMUCTRL_ENAB;
-       switch(tsbsize) {
-       case 64:
-               control |= SABRE_IOMMU_TSBSZ_64K;
-               break;
-       case 128:
-               control |= SABRE_IOMMU_TSBSZ_128K;
-               break;
-       default:
-               prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize);
-               prom_halt();
-               break;
-       }
-       sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
-
-       return 0;
-}
-
-static void __init sabre_pbm_init(struct pci_controller_info *p,
-                                 struct pci_pbm_info *pbm, struct device_node *dp)
+static void __init sabre_pbm_init(struct pci_pbm_info *pbm,
+                                 struct of_device *op)
 {
-       pbm->name = dp->full_name;
-       printk("%s: SABRE PCI Bus Module\n", pbm->name);
-
-       pbm->numa_node = -1;
-
-       pbm->scan_bus = sabre_scan_bus;
-       pbm->pci_ops = &sun4u_pci_ops;
-       pbm->config_space_reg_bits = 8;
-
-       pbm->index = pci_num_pbms++;
-
-       pbm->chip_type = PBM_CHIP_TYPE_SABRE;
-       pbm->parent = p;
-       pbm->prom_node = dp;
-       pci_get_pbm_props(pbm);
-
-       pci_determine_mem_io_space(pbm);
+       psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE);
+       pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR;
+       pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR;
+       pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL;
+       sabre_scan_bus(pbm, &op->dev);
 }
 
-void __init sabre_init(struct device_node *dp, char *model_name)
+static int __devinit sabre_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
        const struct linux_prom64_registers *pr_regs;
-       struct pci_controller_info *p;
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
+       u32 upa_portid, dma_mask;
        struct iommu *iommu;
-       int tsbsize;
+       int tsbsize, err;
        const u32 *vdma;
-       u32 upa_portid, dma_mask;
        u64 clear_irq;
 
-       hummingbird_p = 0;
-       if (!strcmp(model_name, "pci108e,a001"))
-               hummingbird_p = 1;
-       else if (!strcmp(model_name, "SUNW,sabre")) {
-               const char *compat = of_get_property(dp, "compatible", NULL);
-               if (compat && !strcmp(compat, "pci108e,a001"))
-                       hummingbird_p = 1;
-               if (!hummingbird_p) {
-                       struct device_node *dp;
-
-                       /* Of course, Sun has to encode things a thousand
-                        * different ways, inconsistently.
-                        */
-                       for_each_node_by_type(dp, "cpu") {
-                               if (!strcmp(dp->name, "SUNW,UltraSPARC-IIe"))
-                                       hummingbird_p = 1;
-                       }
+       hummingbird_p = (match->data != NULL);
+       if (!hummingbird_p) {
+               struct device_node *cpu_dp;
+
+               /* Of course, Sun has to encode things a thousand
+                * different ways, inconsistently.
+                */
+               for_each_node_by_type(cpu_dp, "cpu") {
+                       if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe"))
+                               hummingbird_p = 1;
                }
        }
 
-       p = kzalloc(sizeof(*p), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
+
+       iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n");
+               goto out_free_controller;
+       }
 
-       iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
-       pbm = &p->pbm_A;
        pbm->iommu = iommu;
 
        upa_portid = of_getintprop_default(dp, "upa-portid", 0xff);
 
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
-
        pbm->portid = upa_portid;
 
        /*
@@ -806,6 +501,11 @@ void __init sabre_init(struct device_node *dp, char *model_name)
         */
        
        pr_regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!pr_regs) {
+               printk(KERN_ERR PFX "No reg property\n");
+               goto out_free_iommu;
+       }
 
        /*
         * First REG in property is base of entire SABRE register space.
@@ -816,22 +516,25 @@ void __init sabre_init(struct device_node *dp, char *model_name)
 
        /* PCI first */
        for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8)
-               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+               upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
        /* Then OBIO */
        for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8)
-               sabre_write(pbm->controller_regs + clear_irq, 0x0UL);
+               upa_writeq(0x0UL, pbm->controller_regs + clear_irq);
 
        /* Error interrupts are enabled later after the bus scan. */
-       sabre_write(pbm->controller_regs + SABRE_PCICTRL,
-                   (SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
-                    SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN));
+       upa_writeq((SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR |
+                   SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN),
+                  pbm->controller_regs + SABRE_PCICTRL);
 
        /* Now map in PCI config space for entire SABRE. */
-       pbm->config_space =
-               (pbm->controller_regs + SABRE_CONFIGSPACE);
+       pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE;
 
        vdma = of_get_property(dp, "virtual-dma", NULL);
+       if (!vdma) {
+               printk(KERN_ERR PFX "No virtual-dma property\n");
+               goto out_free_iommu;
+       }
 
        dma_mask = vdma[0];
        switch(vdma[1]) {
@@ -849,20 +552,58 @@ void __init sabre_init(struct device_node *dp, char *model_name)
                        tsbsize = 128;
                        break;
                default:
-                       prom_printf("SABRE: strange virtual-dma size.\n");
-                       prom_halt();
+                       printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+                       goto out_free_iommu;
        }
 
-       if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
-               goto fatal_memory_error;
+       err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC);
+       if (err)
+               goto out_free_iommu;
 
        /*
         * Look for APB underneath.
         */
-       sabre_pbm_init(p, pbm, dp);
-       return;
+       sabre_pbm_init(pbm, op);
 
-fatal_memory_error:
-       prom_printf("SABRE: Fatal memory allocation error.\n");
-       prom_halt();
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       kfree(pbm->iommu);
+
+out_free_controller:
+       kfree(pbm);
+
+out_err:
+       return err;
+}
+
+static struct of_device_id __initdata sabre_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,a001",
+               .data = (void *) 1,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,a000",
+       },
+       {},
+};
+
+static struct of_platform_driver sabre_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = sabre_match,
+       .probe          = sabre_probe,
+};
+
+static int __init sabre_init(void)
+{
+       return of_register_driver(&sabre_driver, &of_bus_type);
 }
+
+subsys_initcall(sabre_init);
index 9248c6737f0e90b83f0d5aca16240236b3ea4a9f..45d9dba1ba117a9d652727f9968dc13ee690b7cd 100644 (file)
@@ -1,6 +1,6 @@
 /* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support.
  *
- * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2001, 2002, 2003, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
 #include <asm/pstate.h>
 #include <asm/prom.h>
-#include <asm/oplib.h>
+#include <asm/upa.h>
 
 #include "pci_impl.h"
 #include "iommu_common.h"
 
-/* All SCHIZO registers are 64-bits.  The following accessor
- * routines are how they are accessed.  The REG parameter
- * is a physical address.
- */
-#define schizo_read(__reg) \
-({     u64 __ret; \
-       __asm__ __volatile__("ldxa [%1] %2, %0" \
-                            : "=r" (__ret) \
-                            : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory"); \
-       __ret; \
-})
-#define schizo_write(__reg, __val) \
-       __asm__ __volatile__("stxa %0, [%1] %2" \
-                            : /* no outputs */ \
-                            : "r" (__val), "r" (__reg), \
-                              "i" (ASI_PHYS_BYPASS_EC_E) \
-                            : "memory")
+#define DRIVER_NAME    "schizo"
+#define PFX            DRIVER_NAME ": "
 
 /* This is a convention that at least Excalibur and Merlin
  * follow.  I suppose the SCHIZO used in Starcat and friends
@@ -163,25 +146,25 @@ static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,
         * invalidating it before it has a chance to reach
         * main memory.
         */
-       control = schizo_read(strbuf->strbuf_control);
-       schizo_write(strbuf->strbuf_control,
-                    (control | SCHIZO_STRBUF_CTRL_DENAB));
+       control = upa_readq(strbuf->strbuf_control);
+       upa_writeq((control | SCHIZO_STRBUF_CTRL_DENAB),
+                  strbuf->strbuf_control);
        for (i = 0; i < 128; i++) {
                unsigned long val;
 
-               val = schizo_read(err_base + (i * 8UL));
-               schizo_write(err_base + (i * 8UL), 0UL);
+               val = upa_readq(err_base + (i * 8UL));
+               upa_writeq(0UL, err_base + (i * 8UL));
                stc_error_buf[i] = val;
        }
        for (i = 0; i < 16; i++) {
-               stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL));
-               stc_line_buf[i] = schizo_read(line_base + (i * 8UL));
-               schizo_write(tag_base + (i * 8UL), 0UL);
-               schizo_write(line_base + (i * 8UL), 0UL);
+               stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+               stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+               upa_writeq(0UL, tag_base + (i * 8UL));
+               upa_writeq(0UL, line_base + (i * 8UL));
        }
 
        /* OK, state is logged, exit diagnostic mode. */
-       schizo_write(strbuf->strbuf_control, control);
+       upa_writeq(control, strbuf->strbuf_control);
 
        for (i = 0; i < 16; i++) {
                int j, saw_error, first, last;
@@ -258,14 +241,14 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        int i;
 
        spin_lock_irqsave(&iommu->lock, flags);
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        if (control & SCHIZO_IOMMU_CTRL_XLTEERR) {
                unsigned long base;
                char *type_string;
 
                /* Clear the error encountered bit. */
                control &= ~SCHIZO_IOMMU_CTRL_XLTEERR;
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
                case 0:
@@ -295,24 +278,24 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
                 * get as much diagnostic information to the
                 * console as we can.
                 */
-               schizo_write(iommu->iommu_control,
-                            control | SCHIZO_IOMMU_CTRL_DENAB);
+               upa_writeq(control | SCHIZO_IOMMU_CTRL_DENAB,
+                          iommu->iommu_control);
 
                base = pbm->pbm_regs;
 
                for (i = 0; i < 16; i++) {
                        iommu_tag[i] =
-                               schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_TAG + (i * 8UL));
                        iommu_data[i] =
-                               schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL));
+                               upa_readq(base + SCHIZO_IOMMU_DATA + (i * 8UL));
 
                        /* Now clear out the entry. */
-                       schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0);
-                       schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0);
+                       upa_writeq(0, base + SCHIZO_IOMMU_TAG + (i * 8UL));
+                       upa_writeq(0, base + SCHIZO_IOMMU_DATA + (i * 8UL));
                }
 
                /* Leave diagnostic mode. */
-               schizo_write(iommu->iommu_control, control);
+               upa_writeq(control, iommu->iommu_control);
 
                for (i = 0; i < 16; i++) {
                        unsigned long tag, data;
@@ -357,11 +340,12 @@ static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm,
        spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
-static void schizo_check_iommu_error(struct pci_controller_info *p,
+static void schizo_check_iommu_error(struct pci_pbm_info *pbm,
                                     enum schizo_error_type type)
 {
-       schizo_check_iommu_error_pbm(&p->pbm_A, type);
-       schizo_check_iommu_error_pbm(&p->pbm_B, type);
+       schizo_check_iommu_error_pbm(pbm, type);
+       if (pbm->sibling)
+               schizo_check_iommu_error_pbm(pbm->sibling, type);
 }
 
 /* Uncorrectable ECC error status gathering. */
@@ -386,14 +370,13 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
 static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg = pbm->controller_regs + SCHIZO_UE_AFSR;
        unsigned long afar_reg = pbm->controller_regs + SCHIZO_UE_AFAR;
        unsigned long afsr, afar, error_bits;
        int reported, limit;
 
        /* Latch uncorrectable error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -401,7 +384,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear the primary/secondary error status bits. */
@@ -410,7 +393,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
                 SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Uncorrectable Error, primary error type[%s]\n",
@@ -449,7 +432,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id)
        printk("]\n");
 
        /* Interrogate IOMMU for error status. */
-       schizo_check_iommu_error(p, UE_ERR);
+       schizo_check_iommu_error(pbm, UE_ERR);
 
        return IRQ_HANDLED;
 }
@@ -481,7 +464,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
        int reported, limit;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
+       afar = upa_readq(afar_reg);
 
        /* If either of the error pending bits are set in the
         * AFSR, the error status is being actively updated by
@@ -489,7 +472,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
         */
        limit = 1000;
        do {
-               afsr = schizo_read(afsr_reg);
+               afsr = upa_readq(afsr_reg);
        } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit);
 
        /* Clear primary/secondary error status bits. */
@@ -498,7 +481,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id)
                 SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA);
        if (!error_bits)
                return IRQ_NONE;
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: Correctable Error, primary error type[%s]\n",
@@ -600,7 +583,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
        u16 stat;
 
        csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL;
-       csr = schizo_read(csr_reg);
+       csr = upa_readq(csr_reg);
        csr_error_bits =
                csr & (SCHIZO_PCICTRL_BUS_UNUS |
                       SCHIZO_PCICTRL_TTO_ERR |
@@ -610,7 +593,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
                       SCHIZO_PCICTRL_SERR);
        if (csr_error_bits) {
                /* Clear the errors.  */
-               schizo_write(csr_reg, csr);
+               upa_writeq(csr, csr_reg);
 
                /* Log 'em.  */
                if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS)
@@ -650,7 +633,6 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
 static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        unsigned long afsr_reg, afar_reg, base;
        unsigned long afsr, afar, error_bits;
        int reported;
@@ -661,8 +643,8 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
        afar_reg = base + SCHIZO_PCI_AFAR;
 
        /* Latch error status. */
-       afar = schizo_read(afar_reg);
-       afsr = schizo_read(afsr_reg);
+       afar = upa_readq(afar_reg);
+       afsr = upa_readq(afsr_reg);
 
        /* Clear primary/secondary error status bits. */
        error_bits = afsr &
@@ -674,7 +656,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
                 SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS);
        if (!error_bits)
                return schizo_pcierr_intr_other(pbm);
-       schizo_write(afsr_reg, error_bits);
+       upa_writeq(error_bits, afsr_reg);
 
        /* Log the error. */
        printk("%s: PCI Error, primary error type[%s]\n",
@@ -744,7 +726,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
         * a bug in the IOMMU support code or a PCI device driver.
         */
        if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) {
-               schizo_check_iommu_error(p, PCI_ERR);
+               schizo_check_iommu_error(pbm, PCI_ERR);
                pci_scan_for_target_abort(pbm, pbm->pci_bus);
        }
        if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA))
@@ -805,12 +787,11 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
 static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 {
        struct pci_pbm_info *pbm = dev_id;
-       struct pci_controller_info *p = pbm->parent;
        u64 errlog;
 
-       errlog = schizo_read(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG,
-                    errlog & ~(SAFARI_ERRLOG_ERROUT));
+       errlog = upa_readq(pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
+       upa_writeq(errlog & ~(SAFARI_ERRLOG_ERROUT),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRLOG);
 
        if (!(errlog & BUS_ERROR_UNMAP)) {
                printk("%s: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n",
@@ -821,7 +802,7 @@ static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
 
        printk("%s: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n",
               pbm->name);
-       schizo_check_iommu_error(p, SAFARI_ERR);
+       schizo_check_iommu_error(pbm, SAFARI_ERR);
 
        return IRQ_HANDLED;
 }
@@ -863,7 +844,7 @@ static int pbm_routes_this_ino(struct pci_pbm_info *pbm, u32 ino)
  */
 static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -910,10 +891,9 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        /* Enable PCI Error interrupts and clear error
         * bits.
@@ -926,10 +906,10 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
 
        err_no_mask = SCHIZO_PCICTRL_DTO_ERR;
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
                    SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
@@ -938,7 +918,7 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
                    SCHIZO_PCIAFSR_STTO);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR, err_mask);
+       upa_writeq(err_mask, pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR |
                    BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD |
@@ -950,16 +930,16 @@ static void tomatillo_register_error_handlers(struct pci_pbm_info *pbm)
                    BUS_ERROR_APERR | BUS_ERROR_UNMAP |
                    BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL,
-                    (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));
+       upa_writeq((SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)),
+                  pbm->controller_regs + SCHIZO_SAFARI_IRQCTRL);
 }
 
 static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
 {
-       struct of_device *op = of_find_device_by_node(pbm->prom_node);
+       struct of_device *op = of_find_device_by_node(pbm->op->node);
        u64 tmp, err_mask, err_no_mask;
        int err;
 
@@ -1006,10 +986,9 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        }
 
        /* Enable UE and CE interrupts for controller. */
-       schizo_write(pbm->controller_regs + SCHIZO_ECC_CTRL,
-                    (SCHIZO_ECCCTRL_EE |
-                     SCHIZO_ECCCTRL_UE |
-                     SCHIZO_ECCCTRL_CE));
+       upa_writeq((SCHIZO_ECCCTRL_EE |
+                   SCHIZO_ECCCTRL_UE |
+                   SCHIZO_ECCCTRL_CE), pbm->controller_regs + SCHIZO_ECC_CTRL);
 
        err_mask = (SCHIZO_PCICTRL_BUS_UNUS |
                    SCHIZO_PCICTRL_ESLCK |
@@ -1025,18 +1004,18 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
        /* Enable PCI Error interrupts and clear error
         * bits for each PBM.
         */
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
        tmp |= err_mask;
        tmp &= ~err_no_mask;
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_AFSR,
-                    (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
-                     SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
-                     SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
-                     SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
-                     SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
-                     SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS));
+       upa_writeq((SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA |
+                   SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR |
+                   SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS |
+                   SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA |
+                   SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR |
+                   SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS),
+                  pbm->pbm_regs + SCHIZO_PCI_AFSR);
 
        /* Make all Safari error conditions fatal except unmapped
         * errors which we make generate interrupts.
@@ -1063,8 +1042,8 @@ static void schizo_register_error_handlers(struct pci_pbm_info *pbm)
                      BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);
 #endif
 
-       schizo_write(pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL,
-                    (SCHIZO_SAFERRCTRL_EN | err_mask));
+       upa_writeq((SCHIZO_SAFERRCTRL_EN | err_mask),
+                  pbm->controller_regs + SCHIZO_SAFARI_ERRCTRL);
 }
 
 static void pbm_config_busmastering(struct pci_pbm_info *pbm)
@@ -1084,14 +1063,15 @@ static void pbm_config_busmastering(struct pci_pbm_info *pbm)
        pci_config_write8(addr, 64);
 }
 
-static void __init schizo_scan_bus(struct pci_pbm_info *pbm)
+static void __devinit schizo_scan_bus(struct pci_pbm_info *pbm,
+                                     struct device *parent)
 {
        pbm_config_busmastering(pbm);
        pbm->is_66mhz_capable =
-               (of_find_property(pbm->prom_node, "66mhz-capable", NULL)
+               (of_find_property(pbm->op->node, "66mhz-capable", NULL)
                 != NULL);
 
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
                tomatillo_register_error_handlers(pbm);
@@ -1133,12 +1113,12 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
         * streaming buffer and leave the rerun-disable
         * setting however OBP set it.
         */
-       control = schizo_read(pbm->stc.strbuf_control);
+       control = upa_readq(pbm->stc.strbuf_control);
        control &= ~(SCHIZO_STRBUF_CTRL_LPTR |
                     SCHIZO_STRBUF_CTRL_LENAB |
                     SCHIZO_STRBUF_CTRL_DENAB);
        control |= SCHIZO_STRBUF_CTRL_ENAB;
-       schizo_write(pbm->stc.strbuf_control, control);
+       upa_writeq(control, pbm->stc.strbuf_control);
 
        pbm->stc.strbuf_enabled = 1;
 }
@@ -1150,24 +1130,17 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
 
 static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 {
-       struct iommu *iommu = pbm->iommu;
+       static const u32 vdma_default[] = { 0xc0000000, 0x40000000 };
        unsigned long i, tagbase, database;
-       struct property *prop;
-       u32 vdma[2], dma_mask;
+       struct iommu *iommu = pbm->iommu;
        int tsbsize, err;
+       const u32 *vdma;
+       u32 dma_mask;
        u64 control;
 
-       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-       if (prop) {
-               u32 *val = prop->value;
-
-               vdma[0] = val[0];
-               vdma[1] = val[1];
-       } else {
-               /* No property, use default values. */
-               vdma[0] = 0xc0000000;
-               vdma[1] = 0x40000000;
-       }
+       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       if (!vdma)
+               vdma = vdma_default;
 
        dma_mask = vdma[0];
        switch (vdma[1]) {
@@ -1187,9 +1160,9 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
                        break;
 
                default:
-                       prom_printf("SCHIZO: strange virtual-dma size.\n");
-                       prom_halt();
-       };
+                       printk(KERN_ERR PFX "Strange virtual-dma size.\n");
+                       return -EINVAL;
+       }
 
        /* Register addresses, SCHIZO has iommu ctx flushing. */
        iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
@@ -1206,15 +1179,15 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        /*
         * Invalidate TLB Entries.
         */
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control |= SCHIZO_IOMMU_CTRL_DENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA;
 
-       for(i = 0; i < 16; i++) {
-               schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0);
-               schizo_write(pbm->pbm_regs + database + (i * 8UL), 0);
+       for (i = 0; i < 16; i++) {
+               upa_writeq(0, pbm->pbm_regs + tagbase + (i * 8UL));
+               upa_writeq(0, pbm->pbm_regs + database + (i * 8UL));
        }
 
        /* Leave diag mode enabled for full-flushing done
@@ -1222,12 +1195,14 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
         */
        err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask,
                               pbm->numa_node);
-       if (err)
+       if (err) {
+               printk(KERN_ERR PFX "iommu_table_init() fails with %d\n", err);
                return err;
+       }
 
-       schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
 
-       control = schizo_read(iommu->iommu_control);
+       control = upa_readq(iommu->iommu_control);
        control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ);
        switch (tsbsize) {
        case 64:
@@ -1236,10 +1211,10 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
        case 128:
                control |= SCHIZO_IOMMU_TSBSZ_128K;
                break;
-       };
+       }
 
        control |= SCHIZO_IOMMU_CTRL_ENAB;
-       schizo_write(iommu->iommu_control, control);
+       upa_writeq(control, iommu->iommu_control);
 
        return 0;
 }
@@ -1280,12 +1255,11 @@ static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
 
 static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
 {
-       struct property *prop;
        u64 tmp;
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
+       upa_writeq(5, pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
        /* Enable arbiter for all PCI slots.  */
        tmp |= 0xff;
@@ -1294,8 +1268,7 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
            pbm->chip_version >= 0x2)
                tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
 
-       prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL);
-       if (!prop)
+       if (!of_find_property(pbm->op->node, "no-bus-parking", NULL))
                tmp |= SCHIZO_PCICTRL_PARK;
        else
                tmp &= ~SCHIZO_PCICTRL_PARK;
@@ -1311,13 +1284,13 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                        SCHIZO_PCICTRL_RDO_PREF |
                        SCHIZO_PCICTRL_RDL_PREF);
 
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_CTRL);
 
-       tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG);
+       tmp = upa_readq(pbm->pbm_regs + SCHIZO_PCI_DIAG);
        tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB |
                 SCHIZO_PCIDIAG_D_RETRY |
                 SCHIZO_PCIDIAG_D_INTSYNC);
-       schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp);
+       upa_writeq(tmp, pbm->pbm_regs + SCHIZO_PCI_DIAG);
 
        if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
                /* Clear prefetch lengths to workaround a bug in
@@ -1329,17 +1302,16 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
                       TOMATILLO_IOC_RDONE_CPENAB |
                       TOMATILLO_IOC_RDLINE_CPENAB);
 
-               schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR,
-                            tmp);
+               upa_writeq(tmp, pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR);
        }
 }
 
-static int __init schizo_pbm_init(struct pci_controller_info *p,
-                                 struct device_node *dp, u32 portid,
-                                 int chip_type)
+static int __devinit schizo_pbm_init(struct pci_pbm_info *pbm,
+                                    struct of_device *op, u32 portid,
+                                    int chip_type)
 {
        const struct linux_prom64_registers *regs;
-       struct pci_pbm_info *pbm;
+       struct device_node *dp = op->node;
        const char *chipset_name;
        int is_pbm_a, err;
 
@@ -1372,25 +1344,19 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
        regs = of_get_property(dp, "reg", NULL);
 
        is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000);
-       if (is_pbm_a)
-               pbm = &p->pbm_A;
-       else
-               pbm = &p->pbm_B;
 
        pbm->next = pci_pbm_root;
        pci_pbm_root = pbm;
 
        pbm->numa_node = -1;
 
-       pbm->scan_bus = schizo_scan_bus;
        pbm->pci_ops = &sun4u_pci_ops;
        pbm->config_space_reg_bits = 8;
 
        pbm->index = pci_num_pbms++;
 
        pbm->portid = portid;
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
 
        pbm->chip_type = chip_type;
        pbm->chip_version = of_getintprop_default(dp, "version#", 0);
@@ -1420,6 +1386,8 @@ static int __init schizo_pbm_init(struct pci_controller_info *p,
 
        schizo_pbm_strbuf_init(pbm);
 
+       schizo_scan_bus(pbm, &op->dev);
+
        return 0;
 }
 
@@ -1433,62 +1401,104 @@ static inline int portid_compare(u32 x, u32 y, int chip_type)
        return (x == y);
 }
 
-static void __init __schizo_init(struct device_node *dp, char *model_name,
-                                int chip_type)
+static struct pci_pbm_info * __devinit schizo_find_sibling(u32 portid,
+                                                          int chip_type)
 {
-       struct pci_controller_info *p;
+       struct pci_pbm_info *pbm;
+
+       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
+               if (portid_compare(pbm->portid, portid, chip_type))
+                       return pbm;
+       }
+       return NULL;
+}
+
+static int __devinit __schizo_init(struct of_device *op, unsigned long chip_type)
+{
+       struct device_node *dp = op->node;
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
        u32 portid;
+       int err;
 
        portid = of_getintprop_default(dp, "portid", 0xff);
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (portid_compare(pbm->portid, portid, chip_type)) {
-                       if (schizo_pbm_init(pbm->parent, dp,
-                                           portid, chip_type))
-                               goto fatal_memory_error;
-                       return;
-               }
+       err = -ENOMEM;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n");
+               goto out_err;
+       }
+
+       pbm->sibling = schizo_find_sibling(portid, chip_type);
+
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Cannot allocate PBM A iommu.\n");
+               goto out_free_pbm;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       if (schizo_pbm_init(pbm, op, portid, chip_type))
+               goto out_free_iommu;
 
-       p->pbm_A.iommu = iommu;
+       if (pbm->sibling)
+               pbm->sibling->sibling = pbm;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       dev_set_drvdata(&op->dev, pbm);
 
-       p->pbm_B.iommu = iommu;
+       return 0;
 
-       if (schizo_pbm_init(p, dp, portid, chip_type))
-               goto fatal_memory_error;
+out_free_iommu:
+       kfree(pbm->iommu);
 
-       return;
+out_free_pbm:
+       kfree(pbm);
 
-fatal_memory_error:
-       prom_printf("SCHIZO: Fatal memory allocation error.\n");
-       prom_halt();
+out_err:
+       return err;
 }
 
-void __init schizo_init(struct device_node *dp, char *model_name)
+static int __devinit schizo_probe(struct of_device *op,
+                                 const struct of_device_id *match)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO);
+       return __schizo_init(op, (unsigned long) match->data);
 }
 
-void __init schizo_plus_init(struct device_node *dp, char *model_name)
-{
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS);
-}
+/* The ordering of this table is very important.  Some Tomatillo
+ * nodes announce that they are compatible with both pci108e,a801
+ * and pci108e,8001.  So list the chips in reverse chronological
+ * order.
+ */
+static struct of_device_id __initdata schizo_match[] = {
+       {
+               .name = "pci",
+               .compatible = "pci108e,a801",
+               .data = (void *) PBM_CHIP_TYPE_TOMATILLO,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8002",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO_PLUS,
+       },
+       {
+               .name = "pci",
+               .compatible = "pci108e,8001",
+               .data = (void *) PBM_CHIP_TYPE_SCHIZO,
+       },
+       {},
+};
 
-void __init tomatillo_init(struct device_node *dp, char *model_name)
+static struct of_platform_driver schizo_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = schizo_match,
+       .probe          = schizo_probe,
+};
+
+static int __init schizo_init(void)
 {
-       __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO);
+       return of_register_driver(&schizo_driver, &of_bus_type);
 }
+
+subsys_initcall(schizo_init);
index a104c80d319debf8a76c3d658b12fea47cd39d91..e86c73ec167b3ff66d887204f41630d71e7f2d08 100644 (file)
 #include <linux/irq.h>
 #include <linux/msi.h>
 #include <linux/log2.h>
+#include <linux/of_device.h>
 
 #include <asm/iommu.h>
 #include <asm/irq.h>
-#include <asm/upa.h>
-#include <asm/pstate.h>
-#include <asm/oplib.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
 
@@ -27,6 +25,9 @@
 
 #include "pci_sun4v.h"
 
+#define DRIVER_NAME    "pci_sun4v"
+#define PFX            DRIVER_NAME ": "
+
 static unsigned long vpci_major = 1;
 static unsigned long vpci_minor = 1;
 
@@ -41,6 +42,7 @@ struct iommu_batch {
 };
 
 static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
+static int iommu_batch_initialized;
 
 /* Interrupts must be disabled.  */
 static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
@@ -542,15 +544,16 @@ static const struct dma_ops sun4v_dma_ops = {
        .sync_sg_for_cpu                = dma_4v_sync_sg_for_cpu,
 };
 
-static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
+static void __init pci_sun4v_scan_bus(struct pci_pbm_info *pbm,
+                                     struct device *parent)
 {
        struct property *prop;
        struct device_node *dp;
 
-       dp = pbm->prom_node;
+       dp = pbm->op->node;
        prop = of_find_property(dp, "66mhz-capable", NULL);
        pbm->is_66mhz_capable = (prop != NULL);
-       pbm->pci_bus = pci_scan_one_pbm(pbm);
+       pbm->pci_bus = pci_scan_one_pbm(pbm, parent);
 
        /* XXX register error interrupt handlers XXX */
 }
@@ -583,29 +586,22 @@ static unsigned long __init probe_existing_entries(struct pci_pbm_info *pbm,
        return cnt;
 }
 
-static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
+static int __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
 {
+       static const u32 vdma_default[] = { 0x80000000, 0x80000000 };
        struct iommu *iommu = pbm->iommu;
-       struct property *prop;
        unsigned long num_tsb_entries, sz, tsbsize;
-       u32 vdma[2], dma_mask, dma_offset;
-
-       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
-       if (prop) {
-               u32 *val = prop->value;
-
-               vdma[0] = val[0];
-               vdma[1] = val[1];
-       } else {
-               /* No property, use default values. */
-               vdma[0] = 0x80000000;
-               vdma[1] = 0x80000000;
-       }
+       u32 dma_mask, dma_offset;
+       const u32 *vdma;
+
+       vdma = of_get_property(pbm->op->node, "virtual-dma", NULL);
+       if (!vdma)
+               vdma = vdma_default;
 
        if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
-               prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
-                           vdma[0], vdma[1]);
-               prom_halt();
+               printk(KERN_ERR PFX "Strange virtual-dma[%08x:%08x].\n",
+                      vdma[0], vdma[1]);
+               return -EINVAL;
        };
 
        dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
@@ -625,8 +621,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        sz = (sz + 7UL) & ~7UL;
        iommu->arena.map = kzalloc(sz, GFP_KERNEL);
        if (!iommu->arena.map) {
-               prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
-               prom_halt();
+               printk(KERN_ERR PFX "Error, kmalloc(arena.map) failed.\n");
+               return -ENOMEM;
        }
        iommu->arena.limit = num_tsb_entries;
 
@@ -634,6 +630,8 @@ static void __init pci_sun4v_iommu_init(struct pci_pbm_info *pbm)
        if (sz)
                printk("%s: Imported %lu TSB entries from OBP\n",
                       pbm->name, sz);
+
+       return 0;
 }
 
 #ifdef CONFIG_PCI_MSI
@@ -890,29 +888,20 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
 }
 #endif /* !(CONFIG_PCI_MSI) */
 
-static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
-                                     struct device_node *dp, u32 devhandle)
+static int __init pci_sun4v_pbm_init(struct pci_pbm_info *pbm,
+                                    struct of_device *op, u32 devhandle)
 {
-       struct pci_pbm_info *pbm;
-
-       if (devhandle & 0x40)
-               pbm = &p->pbm_B;
-       else
-               pbm = &p->pbm_A;
-
-       pbm->next = pci_pbm_root;
-       pci_pbm_root = pbm;
+       struct device_node *dp = op->node;
+       int err;
 
        pbm->numa_node = of_node_to_nid(dp);
 
-       pbm->scan_bus = pci_sun4v_scan_bus;
        pbm->pci_ops = &sun4v_pci_ops;
        pbm->config_space_reg_bits = 12;
 
        pbm->index = pci_num_pbms++;
 
-       pbm->parent = p;
-       pbm->prom_node = dp;
+       pbm->op = op;
 
        pbm->devhandle = devhandle;
 
@@ -924,82 +913,120 @@ static void __init pci_sun4v_pbm_init(struct pci_controller_info *p,
        pci_determine_mem_io_space(pbm);
 
        pci_get_pbm_props(pbm);
-       pci_sun4v_iommu_init(pbm);
+
+       err = pci_sun4v_iommu_init(pbm);
+       if (err)
+               return err;
+
        pci_sun4v_msi_init(pbm);
+
+       pci_sun4v_scan_bus(pbm, &op->dev);
+
+       pbm->next = pci_pbm_root;
+       pci_pbm_root = pbm;
+
+       return 0;
 }
 
-void __init sun4v_pci_init(struct device_node *dp, char *model_name)
+static int __devinit pci_sun4v_probe(struct of_device *op,
+                                    const struct of_device_id *match)
 {
+       const struct linux_prom64_registers *regs;
        static int hvapi_negotiated = 0;
-       struct pci_controller_info *p;
        struct pci_pbm_info *pbm;
+       struct device_node *dp;
        struct iommu *iommu;
-       struct property *prop;
-       struct linux_prom64_registers *regs;
        u32 devhandle;
-       int i;
+       int i, err;
+
+       dp = op->node;
 
        if (!hvapi_negotiated++) {
-               int err = sun4v_hvapi_register(HV_GRP_PCI,
-                                              vpci_major,
-                                              &vpci_minor);
+               err = sun4v_hvapi_register(HV_GRP_PCI,
+                                          vpci_major,
+                                          &vpci_minor);
 
                if (err) {
-                       prom_printf("SUN4V_PCI: Could not register hvapi, "
-                                   "err=%d\n", err);
-                       prom_halt();
+                       printk(KERN_ERR PFX "Could not register hvapi, "
+                              "err=%d\n", err);
+                       return err;
                }
-               printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
+               printk(KERN_INFO PFX "Registered hvapi major[%lu] minor[%lu]\n",
                       vpci_major, vpci_minor);
 
                dma_ops = &sun4v_dma_ops;
        }
 
-       prop = of_find_property(dp, "reg", NULL);
-       if (!prop) {
-               prom_printf("SUN4V_PCI: Could not find config registers\n");
-               prom_halt();
+       regs = of_get_property(dp, "reg", NULL);
+       err = -ENODEV;
+       if (!regs) {
+               printk(KERN_ERR PFX "Could not find config registers\n");
+               goto out_err;
        }
-       regs = prop->value;
-
        devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff;
 
-       for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
-               if (pbm->devhandle == (devhandle ^ 0x40)) {
-                       pci_sun4v_pbm_init(pbm->parent, dp, devhandle);
-                       return;
+       err = -ENOMEM;
+       if (!iommu_batch_initialized) {
+               for_each_possible_cpu(i) {
+                       unsigned long page = get_zeroed_page(GFP_KERNEL);
+
+                       if (!page)
+                               goto out_err;
+
+                       per_cpu(iommu_batch, i).pglist = (u64 *) page;
                }
+               iommu_batch_initialized = 1;
        }
 
-       for_each_possible_cpu(i) {
-               unsigned long page = get_zeroed_page(GFP_ATOMIC);
-
-               if (!page)
-                       goto fatal_memory_error;
+       pbm = kzalloc(sizeof(*pbm), GFP_KERNEL);
+       if (!pbm) {
+               printk(KERN_ERR PFX "Could not allocate pci_pbm_info\n");
+               goto out_err;
+       }
 
-               per_cpu(iommu_batch, i).pglist = (u64 *) page;
+       iommu = kzalloc(sizeof(struct iommu), GFP_KERNEL);
+       if (!iommu) {
+               printk(KERN_ERR PFX "Could not allocate pbm iommu\n");
+               goto out_free_controller;
        }
 
-       p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
-       if (!p)
-               goto fatal_memory_error;
+       pbm->iommu = iommu;
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+       err = pci_sun4v_pbm_init(pbm, op, devhandle);
+       if (err)
+               goto out_free_iommu;
+
+       dev_set_drvdata(&op->dev, pbm);
+
+       return 0;
+
+out_free_iommu:
+       kfree(pbm->iommu);
 
-       p->pbm_A.iommu = iommu;
+out_free_controller:
+       kfree(pbm);
 
-       iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
-       if (!iommu)
-               goto fatal_memory_error;
+out_err:
+       return err;
+}
 
-       p->pbm_B.iommu = iommu;
+static struct of_device_id __initdata pci_sun4v_match[] = {
+       {
+               .name = "pci",
+               .compatible = "SUNW,sun4v-pci",
+       },
+       {},
+};
 
-       pci_sun4v_pbm_init(p, dp, devhandle);
-       return;
+static struct of_platform_driver pci_sun4v_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = pci_sun4v_match,
+       .probe          = pci_sun4v_probe,
+};
 
-fatal_memory_error:
-       prom_printf("SUN4V_PCI: Fatal memory allocation error.\n");
-       prom_halt();
+static int __init pci_sun4v_init(void)
+{
+       return of_register_driver(&pci_sun4v_driver, &of_bus_type);
 }
+
+subsys_initcall(pci_sun4v_init);
index ecb81f389b0689ff3518448813a1532e96e50af5..e606d46c68159a9c773dfd571fb60b6659882055 100644 (file)
@@ -1,8 +1,9 @@
 /* pci_sun4v_asm: Hypervisor calls for PCI support.
  *
- * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net>
  */
 
+#include <linux/linkage.h>
 #include <asm/hypervisor.h>
 
        /* %o0: devhandle
@@ -14,8 +15,7 @@
         * returns %o0: -status if status was non-zero, else
         *         %o0: num pages mapped
         */
-       .globl  pci_sun4v_iommu_map
-pci_sun4v_iommu_map:
+ENTRY(pci_sun4v_iommu_map)
        mov     %o5, %g1
        mov     HV_FAST_PCI_IOMMU_MAP, %o5
        ta      HV_FAST_TRAP
@@ -24,6 +24,7 @@ pci_sun4v_iommu_map:
        mov     %o1, %o0
 1:     retl
         nop
+ENDPROC(pci_sun4v_iommu_map)
 
        /* %o0: devhandle
         * %o1: tsbid
@@ -31,12 +32,12 @@ pci_sun4v_iommu_map:
         *
         * returns %o0: num ttes demapped
         */
-       .globl  pci_sun4v_iommu_demap
-pci_sun4v_iommu_demap:
+ENTRY(pci_sun4v_iommu_demap)
        mov     HV_FAST_PCI_IOMMU_DEMAP, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o1, %o0
+ENDPROC(pci_sun4v_iommu_demap)
 
        /* %o0: devhandle
         * %o1: tsbid
@@ -45,8 +46,7 @@ pci_sun4v_iommu_demap:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_iommu_getmap
-pci_sun4v_iommu_getmap:
+ENTRY(pci_sun4v_iommu_getmap)
        mov     %o2, %o4
        mov     HV_FAST_PCI_IOMMU_GETMAP, %o5
        ta      HV_FAST_TRAP
@@ -54,6 +54,7 @@ pci_sun4v_iommu_getmap:
        stx     %o2, [%o3]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_iommu_getmap)
 
        /* %o0: devhandle
         * %o1: pci_device
@@ -65,14 +66,14 @@ pci_sun4v_iommu_getmap:
         * If there is an error, the data will be returned
         * as all 1's.
         */
-       .globl  pci_sun4v_config_get
-pci_sun4v_config_get:
+ENTRY(pci_sun4v_config_get)
        mov     HV_FAST_PCI_CONFIG_GET, %o5
        ta      HV_FAST_TRAP
        brnz,a,pn %o1, 1f
         mov    -1, %o2
 1:     retl
         mov    %o2, %o0
+ENDPROC(pci_sun4v_config_get)
 
        /* %o0: devhandle
         * %o1: pci_device
@@ -85,14 +86,14 @@ pci_sun4v_config_get:
         * status will be zero if the operation completed
         * successfully, else -1 if not
         */
-       .globl  pci_sun4v_config_put
-pci_sun4v_config_put:
+ENTRY(pci_sun4v_config_put)
        mov     HV_FAST_PCI_CONFIG_PUT, %o5
        ta      HV_FAST_TRAP
        brnz,a,pn %o1, 1f
         mov    -1, %o1
 1:     retl
         mov    %o1, %o0
+ENDPROC(pci_sun4v_config_put)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -104,12 +105,12 @@ pci_sun4v_config_put:
         * status will be zero if the operation completed
         * successfully, else -1 if not
         */
-       .globl  pci_sun4v_msiq_conf
-pci_sun4v_msiq_conf:
+ENTRY(pci_sun4v_msiq_conf)
        mov     HV_FAST_PCI_MSIQ_CONF, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_conf)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -118,8 +119,7 @@ pci_sun4v_msiq_conf:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_info
-pci_sun4v_msiq_info:
+ENTRY(pci_sun4v_msiq_info)
        mov     %o2, %o4
        mov     HV_FAST_PCI_MSIQ_INFO, %o5
        ta      HV_FAST_TRAP
@@ -127,6 +127,7 @@ pci_sun4v_msiq_info:
        stx     %o2, [%o3]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_info)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -134,13 +135,13 @@ pci_sun4v_msiq_info:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_getvalid
-pci_sun4v_msiq_getvalid:
+ENTRY(pci_sun4v_msiq_getvalid)
        mov     HV_FAST_PCI_MSIQ_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_getvalid)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -148,12 +149,12 @@ pci_sun4v_msiq_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_setvalid
-pci_sun4v_msiq_setvalid:
+ENTRY(pci_sun4v_msiq_setvalid)
        mov     HV_FAST_PCI_MSIQ_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_setvalid)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -161,13 +162,13 @@ pci_sun4v_msiq_setvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_getstate
-pci_sun4v_msiq_getstate:
+ENTRY(pci_sun4v_msiq_getstate)
        mov     HV_FAST_PCI_MSIQ_GETSTATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_getstate)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -175,12 +176,12 @@ pci_sun4v_msiq_getstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_setstate
-pci_sun4v_msiq_setstate:
+ENTRY(pci_sun4v_msiq_setstate)
        mov     HV_FAST_PCI_MSIQ_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_setstate)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -188,13 +189,13 @@ pci_sun4v_msiq_setstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_gethead
-pci_sun4v_msiq_gethead:
+ENTRY(pci_sun4v_msiq_gethead)
        mov     HV_FAST_PCI_MSIQ_GETHEAD, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_gethead)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -202,12 +203,12 @@ pci_sun4v_msiq_gethead:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_sethead
-pci_sun4v_msiq_sethead:
+ENTRY(pci_sun4v_msiq_sethead)
        mov     HV_FAST_PCI_MSIQ_SETHEAD, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_sethead)
 
        /* %o0: devhandle
         * %o1: msiqid
@@ -215,13 +216,13 @@ pci_sun4v_msiq_sethead:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msiq_gettail
-pci_sun4v_msiq_gettail:
+ENTRY(pci_sun4v_msiq_gettail)
        mov     HV_FAST_PCI_MSIQ_GETTAIL, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msiq_gettail)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -229,13 +230,13 @@ pci_sun4v_msiq_gettail:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getvalid
-pci_sun4v_msi_getvalid:
+ENTRY(pci_sun4v_msi_getvalid)
        mov     HV_FAST_PCI_MSI_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -243,12 +244,12 @@ pci_sun4v_msi_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setvalid
-pci_sun4v_msi_setvalid:
+ENTRY(pci_sun4v_msi_setvalid)
        mov     HV_FAST_PCI_MSI_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -256,13 +257,13 @@ pci_sun4v_msi_setvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getmsiq
-pci_sun4v_msi_getmsiq:
+ENTRY(pci_sun4v_msi_getmsiq)
        mov     HV_FAST_PCI_MSI_GETMSIQ, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -271,12 +272,12 @@ pci_sun4v_msi_getmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setmsiq
-pci_sun4v_msi_setmsiq:
+ENTRY(pci_sun4v_msi_setmsiq)
        mov     HV_FAST_PCI_MSI_SETMSIQ, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -284,13 +285,13 @@ pci_sun4v_msi_setmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_getstate
-pci_sun4v_msi_getstate:
+ENTRY(pci_sun4v_msi_getstate)
        mov     HV_FAST_PCI_MSI_GETSTATE, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_getstate)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -298,12 +299,12 @@ pci_sun4v_msi_getstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msi_setstate
-pci_sun4v_msi_setstate:
+ENTRY(pci_sun4v_msi_setstate)
        mov     HV_FAST_PCI_MSI_SETSTATE, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msi_setstate)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -311,13 +312,13 @@ pci_sun4v_msi_setstate:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_getmsiq
-pci_sun4v_msg_getmsiq:
+ENTRY(pci_sun4v_msg_getmsiq)
        mov     HV_FAST_PCI_MSG_GETMSIQ, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_getmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -325,12 +326,12 @@ pci_sun4v_msg_getmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_setmsiq
-pci_sun4v_msg_setmsiq:
+ENTRY(pci_sun4v_msg_setmsiq)
        mov     HV_FAST_PCI_MSG_SETMSIQ, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_setmsiq)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -338,13 +339,13 @@ pci_sun4v_msg_setmsiq:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_getvalid
-pci_sun4v_msg_getvalid:
+ENTRY(pci_sun4v_msg_getvalid)
        mov     HV_FAST_PCI_MSG_GETVALID, %o5
        ta      HV_FAST_TRAP
        stx     %o1, [%o2]
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_getvalid)
 
        /* %o0: devhandle
         * %o1: msinum
@@ -352,10 +353,10 @@ pci_sun4v_msg_getvalid:
         *
         * returns %o0: status
         */
-       .globl  pci_sun4v_msg_setvalid
-pci_sun4v_msg_setvalid:
+ENTRY(pci_sun4v_msg_setvalid)
        mov     HV_FAST_PCI_MSG_SETVALID, %o5
        ta      HV_FAST_TRAP
        retl
         mov    %o0, %o0
+ENDPROC(pci_sun4v_msg_setvalid)
 
index 3bb987a6d03cba183d94039c93e39d94f8bd7509..076cad7f975766aaae812714de7613452d2978cf 100644 (file)
@@ -1,34 +1,17 @@
 /* power.c: Power management driver.
  *
- * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/pm.h>
-#include <linux/syscalls.h>
 #include <linux/reboot.h>
 #include <linux/of_device.h>
 
-#include <asm/system.h>
-#include <asm/auxio.h>
 #include <asm/prom.h>
 #include <asm/io.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
-
-#include <linux/unistd.h>
-
-/*
- * sysctl - toggle power-off restriction for serial console 
- * systems in machine_power_off()
- */
-int scons_pwroff = 1; 
 
 static void __iomem *power_reg;
 
@@ -40,31 +23,6 @@ static irqreturn_t power_handler(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static void (*poweroff_method)(void) = machine_alt_power_off;
-
-void machine_power_off(void)
-{
-       sstate_poweroff();
-       if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
-               if (power_reg) {
-                       /* Both register bits seem to have the
-                        * same effect, so until I figure out
-                        * what the difference is...
-                        */
-                       writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
-               } else {
-                       if (poweroff_method != NULL) {
-                               poweroff_method();
-                               /* not reached */
-                       }
-               }
-       }
-       machine_halt();
-}
-
-void (*pm_power_off)(void) = machine_power_off;
-EXPORT_SYMBOL(pm_power_off);
-
 static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
 {
        if (irq == 0xffffffff)
@@ -85,8 +43,6 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
        printk(KERN_INFO "%s: Control reg at %lx\n",
               op->node->name, res->start);
 
-       poweroff_method = machine_halt;  /* able to use the standard halt */
-
        if (has_button_interrupt(irq, op->node)) {
                if (request_irq(irq,
                                power_handler, 0, "power", NULL) < 0)
@@ -96,7 +52,7 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
        return 0;
 }
 
-static struct of_device_id power_match[] = {
+static struct of_device_id __initdata power_match[] = {
        {
                .name = "power",
        },
@@ -111,8 +67,9 @@ static struct of_platform_driver power_driver = {
        },
 };
 
-void __init power_init(void)
+static int __init power_init(void)
 {
-       of_register_driver(&power_driver, &of_platform_bus_type);
-       return;
+       return of_register_driver(&power_driver, &of_platform_bus_type);
 }
+
+device_initcall(power_init);
index 15f4178592e762d4bbff775679ae80c70e91423d..d5e2acef98771a50da43c2938400551726abd346 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/ptrace.h>
 #include <linux/slab.h>
 #include <linux/user.h>
-#include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/compat.h>
 #include <linux/tick.h>
@@ -31,7 +30,6 @@
 #include <linux/elfcore.h>
 #include <linux/sysrq.h>
 
-#include <asm/oplib.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -46,8 +44,6 @@
 #include <asm/mmu_context.h>
 #include <asm/unistd.h>
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
-#include <asm/reboot.h>
 #include <asm/syscalls.h>
 #include <asm/irq_regs.h>
 #include <asm/smp.h>
@@ -115,35 +111,6 @@ void cpu_idle(void)
        }
 }
 
-void machine_halt(void)
-{
-       sstate_halt();
-       prom_halt();
-       panic("Halt failed!");
-}
-
-void machine_alt_power_off(void)
-{
-       sstate_poweroff();
-       prom_halt_power_off();
-       panic("Power-off failed!");
-}
-
-void machine_restart(char * cmd)
-{
-       char *p;
-       
-       sstate_reboot();
-       p = strchr (reboot_command, '\n');
-       if (p) *p = 0;
-       if (cmd)
-               prom_reboot(cmd);
-       if (*reboot_command)
-               prom_reboot(reboot_command);
-       prom_reboot("");
-       panic("Reboot failed!");
-}
-
 #ifdef CONFIG_COMPAT
 static void show_regwindow32(struct pt_regs *regs)
 {
@@ -248,7 +215,6 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs,
        global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7];
 
        if (regs->tstate & TSTATE_PRIV) {
-               struct thread_info *tp = current_thread_info();
                struct reg_window *rw;
 
                rw = (struct reg_window *)
@@ -304,7 +270,6 @@ void __trigger_all_cpu_backtrace(void)
 
        for_each_online_cpu(cpu) {
                struct global_reg_snapshot *gp = &global_reg_snapshot[cpu];
-               struct thread_info *tp;
 
                __global_reg_poll(gp);
 
index 7151513f156e89ce428c0897e29ee7f4acfbde70..dbba82f9b142c3e950911bdcb4a0359707b1b5bd 100644 (file)
@@ -38,7 +38,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 {
        struct device_node *np;
 
-       for (np = allnodes; np != 0; np = np->allnext)
+       for (np = allnodes; np; np = np->allnext)
                if (np->node == handle)
                        break;
 
@@ -59,6 +59,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
 }
 EXPORT_SYMBOL(of_getintprop_default);
 
+DEFINE_MUTEX(of_set_property_mutex);
+EXPORT_SYMBOL(of_set_property_mutex);
+
 int of_set_property(struct device_node *dp, const char *name, void *val, int len)
 {
        struct property **prevp;
@@ -82,7 +85,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
                        void *old_val = prop->value;
                        int ret;
 
+                       mutex_lock(&of_set_property_mutex);
                        ret = prom_setprop(dp->node, name, val, len);
+                       mutex_unlock(&of_set_property_mutex);
+
                        err = -EINVAL;
                        if (ret >= 0) {
                                prop->value = new_val;
@@ -945,22 +951,30 @@ static void __init irq_trans_init(struct device_node *dp)
                for (i = 0; i < ARRAY_SIZE(pci_irq_trans_table); i++) {
                        struct irq_trans *t = &pci_irq_trans_table[i];
 
-                       if (!strcmp(model, t->name))
-                               return t->init(dp);
+                       if (!strcmp(model, t->name)) {
+                               t->init(dp);
+                               return;
+                       }
                }
        }
 #endif
 #ifdef CONFIG_SBUS
        if (!strcmp(dp->name, "sbus") ||
-           !strcmp(dp->name, "sbi"))
-               return sbus_irq_trans_init(dp);
+           !strcmp(dp->name, "sbi")) {
+               sbus_irq_trans_init(dp);
+               return;
+       }
 #endif
        if (!strcmp(dp->name, "fhc") &&
-           !strcmp(dp->parent->name, "central"))
-               return central_irq_trans_init(dp);
+           !strcmp(dp->parent->name, "central")) {
+               central_irq_trans_init(dp);
+               return;
+       }
        if (!strcmp(dp->name, "virtual-devices") ||
-           !strcmp(dp->name, "niu"))
-               return sun4v_vdev_irq_trans_init(dp);
+           !strcmp(dp->name, "niu")) {
+               sun4v_vdev_irq_trans_init(dp);
+               return;
+       }
 }
 
 static int is_root_node(const struct device_node *dp)
@@ -1231,32 +1245,49 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
 
        if (parent != NULL) {
                if (!strcmp(parent->type, "pci") ||
-                   !strcmp(parent->type, "pciex"))
-                       return pci_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "sbus"))
-                       return sbus_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "upa"))
-                       return upa_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "ebus"))
-                       return ebus_path_component(dp, tmp_buf);
+                   !strcmp(parent->type, "pciex")) {
+                       pci_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "sbus")) {
+                       sbus_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "upa")) {
+                       upa_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "ebus")) {
+                       ebus_path_component(dp, tmp_buf);
+                       return;
+               }
                if (!strcmp(parent->name, "usb") ||
-                   !strcmp(parent->name, "hub"))
-                       return usb_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "i2c"))
-                       return i2c_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "firewire"))
-                       return ieee1394_path_component(dp, tmp_buf);
-               if (!strcmp(parent->type, "virtual-devices"))
-                       return vdev_path_component(dp, tmp_buf);
-
+                   !strcmp(parent->name, "hub")) {
+                       usb_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "i2c")) {
+                       i2c_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "firewire")) {
+                       ieee1394_path_component(dp, tmp_buf);
+                       return;
+               }
+               if (!strcmp(parent->type, "virtual-devices")) {
+                       vdev_path_component(dp, tmp_buf);
+                       return;
+               }
                /* "isa" is handled with platform naming */
        }
 
        /* Use platform naming convention.  */
-       if (tlb_type == hypervisor)
-               return sun4v_path_component(dp, tmp_buf);
-       else
-               return sun4u_path_component(dp, tmp_buf);
+       if (tlb_type == hypervisor) {
+               sun4v_path_component(dp, tmp_buf);
+               return;
+       } else {
+               sun4u_path_component(dp, tmp_buf);
+       }
 }
 
 static char * __init build_path_component(struct device_node *dp)
diff --git a/arch/sparc64/kernel/psycho_common.c b/arch/sparc64/kernel/psycho_common.c
new file mode 100644 (file)
index 0000000..7909964
--- /dev/null
@@ -0,0 +1,470 @@
+/* psycho_common.c: Code common to PSYCHO and derivative PCI controllers.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
+#include <asm/upa.h>
+
+#include "pci_impl.h"
+#include "iommu_common.h"
+#include "psycho_common.h"
+
+#define  PSYCHO_STRBUF_CTRL_DENAB      0x0000000000000002UL
+#define  PSYCHO_STCERR_WRITE           0x0000000000000002UL
+#define  PSYCHO_STCERR_READ            0x0000000000000001UL
+#define  PSYCHO_STCTAG_PPN             0x0fffffff00000000UL
+#define  PSYCHO_STCTAG_VPN             0x00000000ffffe000UL
+#define  PSYCHO_STCTAG_VALID           0x0000000000000002UL
+#define  PSYCHO_STCTAG_WRITE           0x0000000000000001UL
+#define  PSYCHO_STCLINE_LINDX          0x0000000001e00000UL
+#define  PSYCHO_STCLINE_SPTR           0x00000000001f8000UL
+#define  PSYCHO_STCLINE_LADDR          0x0000000000007f00UL
+#define  PSYCHO_STCLINE_EPTR           0x00000000000000fcUL
+#define  PSYCHO_STCLINE_VALID          0x0000000000000002UL
+#define  PSYCHO_STCLINE_FOFN           0x0000000000000001UL
+
+static DEFINE_SPINLOCK(stc_buf_lock);
+static unsigned long stc_error_buf[128];
+static unsigned long stc_tag_buf[16];
+static unsigned long stc_line_buf[16];
+
+static void psycho_check_stc_error(struct pci_pbm_info *pbm)
+{
+       unsigned long err_base, tag_base, line_base;
+       struct strbuf *strbuf = &pbm->stc;
+       u64 control;
+       int i;
+
+       if (!strbuf->strbuf_control)
+               return;
+
+       err_base = strbuf->strbuf_err_stat;
+       tag_base = strbuf->strbuf_tag_diag;
+       line_base = strbuf->strbuf_line_diag;
+
+       spin_lock(&stc_buf_lock);
+
+       /* This is __REALLY__ dangerous.  When we put the streaming
+        * buffer into diagnostic mode to probe it's tags and error
+        * status, we _must_ clear all of the line tag valid bits
+        * before re-enabling the streaming buffer.  If any dirty data
+        * lives in the STC when we do this, we will end up
+        * invalidating it before it has a chance to reach main
+        * memory.
+        */
+       control = upa_readq(strbuf->strbuf_control);
+       upa_writeq(control | PSYCHO_STRBUF_CTRL_DENAB, strbuf->strbuf_control);
+       for (i = 0; i < 128; i++) {
+               u64 val;
+
+               val = upa_readq(err_base + (i * 8UL));
+               upa_writeq(0UL, err_base + (i * 8UL));
+               stc_error_buf[i] = val;
+       }
+       for (i = 0; i < 16; i++) {
+               stc_tag_buf[i] = upa_readq(tag_base + (i * 8UL));
+               stc_line_buf[i] = upa_readq(line_base + (i * 8UL));
+               upa_writeq(0UL, tag_base + (i * 8UL));
+               upa_writeq(0UL, line_base + (i * 8UL));
+       }
+
+       /* OK, state is logged, exit diagnostic mode. */
+       upa_writeq(control, strbuf->strbuf_control);
+
+       for (i = 0; i < 16; i++) {
+               int j, saw_error, first, last;
+
+               saw_error = 0;
+               first = i * 8;
+               last = first + 8;
+               for (j = first; j < last; j++) {
+                       u64 errval = stc_error_buf[j];
+                       if (errval != 0) {
+                               saw_error++;
+                               printk(KERN_ERR "%s: STC_ERR(%d)[wr(%d)"
+                                      "rd(%d)]\n",
+                                      pbm->name,
+                                      j,
+                                      (errval & PSYCHO_STCERR_WRITE) ? 1 : 0,
+                                      (errval & PSYCHO_STCERR_READ) ? 1 : 0);
+                       }
+               }
+               if (saw_error != 0) {
+                       u64 tagval = stc_tag_buf[i];
+                       u64 lineval = stc_line_buf[i];
+                       printk(KERN_ERR "%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)"
+                              "V(%d)W(%d)]\n",
+                              pbm->name,
+                              i,
+                              ((tagval & PSYCHO_STCTAG_PPN) >> 19UL),
+                              (tagval & PSYCHO_STCTAG_VPN),
+                              ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0),
+                              ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0));
+                       printk(KERN_ERR "%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)"
+                              "LADDR(%lx)EP(%lx)V(%d)FOFN(%d)]\n",
+                              pbm->name,
+                              i,
+                              ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL),
+                              ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL),
+                              ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL),
+                              ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL),
+                              ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0),
+                              ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0));
+               }
+       }
+
+       spin_unlock(&stc_buf_lock);
+}
+
+#define PSYCHO_IOMMU_TAG               0xa580UL
+#define PSYCHO_IOMMU_DATA              0xa600UL
+
+static void psycho_record_iommu_tags_and_data(struct pci_pbm_info *pbm,
+                                             u64 *tag, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               unsigned long base = pbm->controller_regs;
+               unsigned long off = i * 8UL;
+
+               tag[i] = upa_readq(base + PSYCHO_IOMMU_TAG+off);
+               data[i] = upa_readq(base + PSYCHO_IOMMU_DATA+off);
+
+               /* Now clear out the entry. */
+               upa_writeq(0, base + PSYCHO_IOMMU_TAG + off);
+               upa_writeq(0, base + PSYCHO_IOMMU_DATA + off);
+       }
+}
+
+#define  PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL)
+#define  PSYCHO_IOMMU_TAG_ERR   (0x1UL << 22UL)
+#define  PSYCHO_IOMMU_TAG_WRITE         (0x1UL << 21UL)
+#define  PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL)
+#define  PSYCHO_IOMMU_TAG_SIZE  (0x1UL << 19UL)
+#define  PSYCHO_IOMMU_TAG_VPAGE         0x7ffffUL
+#define  PSYCHO_IOMMU_DATA_VALID (1UL << 30UL)
+#define  PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL)
+#define  PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL
+
+static void psycho_dump_iommu_tags_and_data(struct pci_pbm_info *pbm,
+                                           u64 *tag, u64 *data)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               u64 tag_val, data_val;
+               const char *type_str;
+               tag_val = tag[i];
+               if (!(tag_val & PSYCHO_IOMMU_TAG_ERR))
+                       continue;
+
+               data_val = data[i];
+               switch((tag_val & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) {
+               case 0:
+                       type_str = "Protection Error";
+                       break;
+               case 1:
+                       type_str = "Invalid Error";
+                       break;
+               case 2:
+                       type_str = "TimeOut Error";
+                       break;
+               case 3:
+               default:
+                       type_str = "ECC Error";
+                       break;
+               }
+
+               printk(KERN_ERR "%s: IOMMU TAG(%d)[error(%s) wr(%d) "
+                      "str(%d) sz(%dK) vpg(%08lx)]\n",
+                      pbm->name, i, type_str,
+                      ((tag_val & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
+                      ((tag_val & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
+                      ((tag_val & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
+                      (tag_val & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
+               printk(KERN_ERR "%s: IOMMU DATA(%d)[valid(%d) cache(%d) "
+                      "ppg(%016lx)]\n",
+                      pbm->name, i,
+                      ((data_val & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
+                      ((data_val & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
+                      (data_val & PSYCHO_IOMMU_DATA_PPAGE)<<IOMMU_PAGE_SHIFT);
+       }
+}
+
+#define  PSYCHO_IOMMU_CTRL_XLTESTAT    0x0000000006000000UL
+#define  PSYCHO_IOMMU_CTRL_XLTEERR     0x0000000001000000UL
+
+void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+                             unsigned long afsr,
+                             unsigned long afar,
+                             enum psycho_error_type type)
+{
+       u64 control, iommu_tag[16], iommu_data[16];
+       struct iommu *iommu = pbm->iommu;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu->lock, flags);
+       control = upa_readq(iommu->iommu_control);
+       if (control & PSYCHO_IOMMU_CTRL_XLTEERR) {
+               const char *type_str;
+
+               control &= ~PSYCHO_IOMMU_CTRL_XLTEERR;
+               upa_writeq(control, iommu->iommu_control);
+
+               switch ((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) {
+               case 0:
+                       type_str = "Protection Error";
+                       break;
+               case 1:
+                       type_str = "Invalid Error";
+                       break;
+               case 2:
+                       type_str = "TimeOut Error";
+                       break;
+               case 3:
+               default:
+                       type_str = "ECC Error";
+                       break;
+               };
+               printk(KERN_ERR "%s: IOMMU Error, type[%s]\n",
+                      pbm->name, type_str);
+
+               /* It is very possible for another DVMA to occur while
+                * we do this probe, and corrupt the system further.
+                * But we are so screwed at this point that we are
+                * likely to crash hard anyways, so get as much
+                * diagnostic information to the console as we can.
+                */
+               psycho_record_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+               psycho_dump_iommu_tags_and_data(pbm, iommu_tag, iommu_data);
+       }
+       psycho_check_stc_error(pbm);
+       spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+#define  PSYCHO_PCICTRL_SBH_ERR         0x0000000800000000UL
+#define  PSYCHO_PCICTRL_SERR    0x0000000400000000UL
+
+static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm)
+{
+       irqreturn_t ret = IRQ_NONE;
+       u64 csr, csr_error_bits;
+       u16 stat, *addr;
+
+       csr = upa_readq(pbm->pci_csr);
+       csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR);
+       if (csr_error_bits) {
+               /* Clear the errors.  */
+               upa_writeq(csr, pbm->pci_csr);
+
+               /* Log 'em.  */
+               if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR)
+                       printk(KERN_ERR "%s: PCI streaming byte hole "
+                              "error asserted.\n", pbm->name);
+               if (csr_error_bits & PSYCHO_PCICTRL_SERR)
+                       printk(KERN_ERR "%s: PCI SERR signal asserted.\n",
+                              pbm->name);
+               ret = IRQ_HANDLED;
+       }
+       addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno,
+                                       0, PCI_STATUS);
+       pci_config_read16(addr, &stat);
+       if (stat & (PCI_STATUS_PARITY |
+                   PCI_STATUS_SIG_TARGET_ABORT |
+                   PCI_STATUS_REC_TARGET_ABORT |
+                   PCI_STATUS_REC_MASTER_ABORT |
+                   PCI_STATUS_SIG_SYSTEM_ERROR)) {
+               printk(KERN_ERR "%s: PCI bus error, PCI_STATUS[%04x]\n",
+                      pbm->name, stat);
+               pci_config_write16(addr, 0xffff);
+               ret = IRQ_HANDLED;
+       }
+       return ret;
+}
+
+#define  PSYCHO_PCIAFSR_PMA    0x8000000000000000UL
+#define  PSYCHO_PCIAFSR_PTA    0x4000000000000000UL
+#define  PSYCHO_PCIAFSR_PRTRY  0x2000000000000000UL
+#define  PSYCHO_PCIAFSR_PPERR  0x1000000000000000UL
+#define  PSYCHO_PCIAFSR_SMA    0x0800000000000000UL
+#define  PSYCHO_PCIAFSR_STA    0x0400000000000000UL
+#define  PSYCHO_PCIAFSR_SRTRY  0x0200000000000000UL
+#define  PSYCHO_PCIAFSR_SPERR  0x0100000000000000UL
+#define  PSYCHO_PCIAFSR_RESV1  0x00ff000000000000UL
+#define  PSYCHO_PCIAFSR_BMSK   0x0000ffff00000000UL
+#define  PSYCHO_PCIAFSR_BLK    0x0000000080000000UL
+#define  PSYCHO_PCIAFSR_RESV2  0x0000000040000000UL
+#define  PSYCHO_PCIAFSR_MID    0x000000003e000000UL
+#define  PSYCHO_PCIAFSR_RESV3  0x0000000001ffffffUL
+
+irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
+{
+       struct pci_pbm_info *pbm = dev_id;
+       u64 afsr, afar, error_bits;
+       int reported;
+
+       afsr = upa_readq(pbm->pci_afsr);
+       afar = upa_readq(pbm->pci_afar);
+       error_bits = afsr &
+               (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |
+                PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |
+                PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |
+                PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);
+       if (!error_bits)
+               return psycho_pcierr_intr_other(pbm);
+       upa_writeq(error_bits, pbm->pci_afsr);
+       printk(KERN_ERR "%s: PCI Error, primary error type[%s]\n",
+              pbm->name,
+              (((error_bits & PSYCHO_PCIAFSR_PMA) ?
+                "Master Abort" :
+                ((error_bits & PSYCHO_PCIAFSR_PTA) ?
+                 "Target Abort" :
+                 ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?
+                  "Excessive Retries" :
+                  ((error_bits & PSYCHO_PCIAFSR_PPERR) ?
+                   "Parity Error" : "???"))))));
+       printk(KERN_ERR "%s: bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",
+              pbm->name,
+              (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,
+              (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,
+              (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);
+       printk(KERN_ERR "%s: PCI AFAR [%016lx]\n", pbm->name, afar);
+       printk(KERN_ERR "%s: PCI Secondary errors [", pbm->name);
+       reported = 0;
+       if (afsr & PSYCHO_PCIAFSR_SMA) {
+               reported++;
+               printk("(Master Abort)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_STA) {
+               reported++;
+               printk("(Target Abort)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_SRTRY) {
+               reported++;
+               printk("(Excessive Retries)");
+       }
+       if (afsr & PSYCHO_PCIAFSR_SPERR) {
+               reported++;
+               printk("(Parity Error)");
+       }
+       if (!reported)
+               printk("(none)");
+       printk("]\n");
+
+       if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {
+               psycho_check_iommu_error(pbm, afsr, afar, PCI_ERR);
+               pci_scan_for_target_abort(pbm, pbm->pci_bus);
+       }
+       if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))
+               pci_scan_for_master_abort(pbm, pbm->pci_bus);
+
+       if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))
+               pci_scan_for_parity_error(pbm, pbm->pci_bus);
+
+       return IRQ_HANDLED;
+}
+
+static void psycho_iommu_flush(struct pci_pbm_info *pbm)
+{
+       int i;
+
+       for (i = 0; i < 16; i++) {
+               unsigned long off = i * 8;
+
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_TAG + off);
+               upa_writeq(0, pbm->controller_regs + PSYCHO_IOMMU_DATA + off);
+       }
+}
+
+#define PSYCHO_IOMMU_CONTROL           0x0200UL
+#define  PSYCHO_IOMMU_CTRL_TSBSZ       0x0000000000070000UL
+#define  PSYCHO_IOMMU_TSBSZ_1K         0x0000000000000000UL
+#define  PSYCHO_IOMMU_TSBSZ_2K         0x0000000000010000UL
+#define  PSYCHO_IOMMU_TSBSZ_4K         0x0000000000020000UL
+#define  PSYCHO_IOMMU_TSBSZ_8K         0x0000000000030000UL
+#define  PSYCHO_IOMMU_TSBSZ_16K        0x0000000000040000UL
+#define  PSYCHO_IOMMU_TSBSZ_32K        0x0000000000050000UL
+#define  PSYCHO_IOMMU_TSBSZ_64K        0x0000000000060000UL
+#define  PSYCHO_IOMMU_TSBSZ_128K       0x0000000000070000UL
+#define  PSYCHO_IOMMU_CTRL_TBWSZ       0x0000000000000004UL
+#define  PSYCHO_IOMMU_CTRL_DENAB       0x0000000000000002UL
+#define  PSYCHO_IOMMU_CTRL_ENAB        0x0000000000000001UL
+#define PSYCHO_IOMMU_FLUSH             0x0210UL
+#define PSYCHO_IOMMU_TSBBASE           0x0208UL
+
+int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                     u32 dvma_offset, u32 dma_mask,
+                     unsigned long write_complete_offset)
+{
+       struct iommu *iommu = pbm->iommu;
+       u64 control;
+       int err;
+
+       iommu->iommu_control  = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
+       iommu->iommu_tsbbase  = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
+       iommu->iommu_flush    = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+       iommu->iommu_tags     = pbm->controller_regs + PSYCHO_IOMMU_TAG;
+       iommu->write_complete_reg = (pbm->controller_regs +
+                                    write_complete_offset);
+
+       iommu->iommu_ctxflush = 0;
+
+       control = upa_readq(iommu->iommu_control);
+       control |= PSYCHO_IOMMU_CTRL_DENAB;
+       upa_writeq(control, iommu->iommu_control);
+
+       psycho_iommu_flush(pbm);
+
+       /* Leave diag mode enabled for full-flushing done in pci_iommu.c */
+       err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+                              dvma_offset, dma_mask, pbm->numa_node);
+       if (err)
+               return err;
+
+       upa_writeq(__pa(iommu->page_table), iommu->iommu_tsbbase);
+
+       control = upa_readq(iommu->iommu_control);
+       control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ);
+       control |= PSYCHO_IOMMU_CTRL_ENAB;
+
+       switch (tsbsize) {
+       case 64:
+               control |= PSYCHO_IOMMU_TSBSZ_64K;
+               break;
+       case 128:
+               control |= PSYCHO_IOMMU_TSBSZ_128K;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       upa_writeq(control, iommu->iommu_control);
+
+       return 0;
+
+}
+
+void psycho_pbm_init_common(struct pci_pbm_info *pbm, struct of_device *op,
+                           const char *chip_name, int chip_type)
+{
+       struct device_node *dp = op->node;
+
+       pbm->name = dp->full_name;
+       pbm->numa_node = -1;
+       pbm->chip_type = chip_type;
+       pbm->chip_version = of_getintprop_default(dp, "version#", 0);
+       pbm->chip_revision = of_getintprop_default(dp, "module-revision#", 0);
+       pbm->op = op;
+       pbm->pci_ops = &sun4u_pci_ops;
+       pbm->config_space_reg_bits = 8;
+       pbm->index = pci_num_pbms++;
+       pci_get_pbm_props(pbm);
+       pci_determine_mem_io_space(pbm);
+
+       printk(KERN_INFO "%s: %s PCI Bus Module ver[%x:%x]\n",
+              pbm->name, chip_name,
+              pbm->chip_version, pbm->chip_revision);
+}
diff --git a/arch/sparc64/kernel/psycho_common.h b/arch/sparc64/kernel/psycho_common.h
new file mode 100644 (file)
index 0000000..092c278
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _PSYCHO_COMMON_H
+#define _PSYCHO_COMMON_H
+
+/* U2P Programmer's Manual, page 13-55, configuration space
+ * address format:
+ * 
+ *  32             24 23 16 15    11 10       8 7   2  1 0
+ * ---------------------------------------------------------
+ * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
+ * ---------------------------------------------------------
+ */
+#define PSYCHO_CONFIG_BASE(PBM)        \
+       ((PBM)->config_space | (1UL << 24))
+#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG)  \
+       (((unsigned long)(BUS)   << 16) |       \
+        ((unsigned long)(DEVFN) << 8)  |       \
+        ((unsigned long)(REG)))
+
+static inline void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm,
+                                            unsigned char bus,
+                                            unsigned int devfn,
+                                            int where)
+{
+       return (void *)
+               (PSYCHO_CONFIG_BASE(pbm) |
+                PSYCHO_CONFIG_ENCODE(bus, devfn, where));
+}
+
+enum psycho_error_type {
+       UE_ERR, CE_ERR, PCI_ERR
+};
+
+extern void psycho_check_iommu_error(struct pci_pbm_info *pbm,
+                                    unsigned long afsr,
+                                    unsigned long afar,
+                                    enum psycho_error_type type);
+
+extern irqreturn_t psycho_pcierr_intr(int irq, void *dev_id);
+
+extern int psycho_iommu_init(struct pci_pbm_info *pbm, int tsbsize,
+                            u32 dvma_offset, u32 dma_mask,
+                            unsigned long write_complete_offset);
+
+extern void psycho_pbm_init_common(struct pci_pbm_info *pbm,
+                                  struct of_device *op,
+                                  const char *chip_name, int chip_type);
+
+#endif /* _PSYCHO_COMMON_H */
index 10306e476e388370812cb5f1f03c32d9c61879ef..f43adbc773caca890f96a214647a7f63ee225531 100644 (file)
@@ -1050,31 +1050,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
        return ret;
 }
 
-asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
+asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 {
        int ret = 0;
 
        /* do the secure computing check first */
        secure_computing(regs->u_regs[UREG_G1]);
 
-       if (unlikely(current->audit_context) && syscall_exit_p) {
-               unsigned long tstate = regs->tstate;
-               int result = AUDITSC_SUCCESS;
-
-               if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
-                       result = AUDITSC_FAILURE;
-
-               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
-       }
-
-       if (test_thread_flag(TIF_SYSCALL_TRACE)) {
-               if (syscall_exit_p)
-                       tracehook_report_syscall_exit(regs, 0);
-               else
-                       ret = tracehook_report_syscall_entry(regs);
-       }
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               ret = tracehook_report_syscall_entry(regs);
 
-       if (unlikely(current->audit_context) && !syscall_exit_p && !ret)
+       if (unlikely(current->audit_context) && !ret)
                audit_syscall_entry((test_thread_flag(TIF_32BIT) ?
                                     AUDIT_ARCH_SPARC :
                                     AUDIT_ARCH_SPARC64),
@@ -1086,3 +1072,19 @@ asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p)
 
        return ret;
 }
+
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+       if (unlikely(current->audit_context)) {
+               unsigned long tstate = regs->tstate;
+               int result = AUDITSC_SUCCESS;
+
+               if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+                       result = AUDITSC_FAILURE;
+
+               audit_syscall_exit(result, regs->u_regs[UREG_I0]);
+       }
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, 0);
+}
diff --git a/arch/sparc64/kernel/reboot.c b/arch/sparc64/kernel/reboot.c
new file mode 100644 (file)
index 0000000..ef89d3d
--- /dev/null
@@ -0,0 +1,53 @@
+/* reboot.c: reboot/shutdown/halt/poweroff handling
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+
+#include <asm/system.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+
+/* sysctl - toggle power-off restriction for serial console
+ * systems in machine_power_off()
+ */
+int scons_pwroff = 1;
+
+/* This isn't actually used, it exists merely to satisfy the
+ * reference in kernel/sys.c
+ */
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_power_off(void)
+{
+       if (strcmp(of_console_device->type, "serial") || scons_pwroff)
+               prom_halt_power_off();
+
+       prom_halt();
+}
+
+void machine_halt(void)
+{
+       prom_halt();
+       panic("Halt failed!");
+}
+
+void machine_restart(char *cmd)
+{
+       char *p;
+
+       p = strchr(reboot_command, '\n');
+       if (p)
+               *p = 0;
+       if (cmd)
+               prom_reboot(cmd);
+       if (*reboot_command)
+               prom_reboot(reboot_command);
+       prom_reboot("");
+       panic("Reboot failed!");
+}
+
index e33a8a660e9e5ab0ca27199732b7758dde3d8819..2ead310066d1b60b4f6098c2f18aa37d3d175581 100644 (file)
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/page.h>
-#include <asm/sbus.h>
 #include <asm/io.h>
 #include <asm/upa.h>
 #include <asm/cache.h>
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/oplib.h>
 #include <asm/starfire.h>
 
 #include "iommu_common.h"
 #define STRBUF_TAG_VALID       0x02UL
 
 /* Enable 64-bit DVMA mode for the given device. */
-void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
+void sbus_set_sbus64(struct device *dev, int bursts)
 {
-       struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
-       int slot = sdev->slot;
+       struct iommu *iommu = dev->archdata.iommu;
+       struct of_device *op = to_of_device(dev);
+       const struct linux_prom_registers *regs;
        unsigned long cfg_reg;
+       int slot;
        u64 val;
 
+       regs = of_get_property(op->node, "reg", NULL);
+       if (!regs) {
+               printk(KERN_ERR "sbus_set_sbus64: Cannot find regs for %s\n",
+                      op->node->full_name);
+               return;
+       }
+       slot = regs->which_io;
+
        cfg_reg = iommu->write_complete_reg;
        switch (slot) {
        case 0:
@@ -191,10 +203,9 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
        return imap + diff;
 }
 
-unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
+static unsigned int sbus_build_irq(struct of_device *op, unsigned int ino)
 {
-       struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long imap, iclr;
        int sbus_level = 0;
@@ -255,12 +266,12 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
 #define  SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long afsr_reg, afar_reg;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        afsr_reg = reg_base + SYSIO_UE_AFSR;
        afar_reg = reg_base + SYSIO_UE_AFAR;
@@ -275,9 +286,11 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
                 SYSIO_UEAFSR_SPIO | SYSIO_UEAFSR_SDRD | SYSIO_UEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        /* Log the error. */
        printk("SYSIO[%x]: Uncorrectable ECC Error, primary error type[%s]\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_UEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SYSIO_UEAFSR_PDRD) ?
@@ -285,12 +298,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
                  ((error_bits & SYSIO_UEAFSR_PDWR) ?
                   "DVMA Write" : "???")))));
        printk("SYSIO[%x]: DOFF[%lx] SIZE[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_UEAFSR_DOFF) >> 45UL,
               (afsr & SYSIO_UEAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_UEAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-       printk("SYSIO[%x]: Secondary UE errors [", sbus->portid);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+       printk("SYSIO[%x]: Secondary UE errors [", portid);
        reported = 0;
        if (afsr & SYSIO_UEAFSR_SPIO) {
                reported++;
@@ -327,12 +340,12 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
 #define  SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned long afsr_reg, afar_reg;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        afsr_reg = reg_base + SYSIO_CE_AFSR;
        afar_reg = reg_base + SYSIO_CE_AFAR;
@@ -347,8 +360,10 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
                 SYSIO_CEAFSR_SPIO | SYSIO_CEAFSR_SDRD | SYSIO_CEAFSR_SDWR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        printk("SYSIO[%x]: Correctable ECC Error, primary error type[%s]\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_CEAFSR_PPIO) ?
                 "PIO" :
                 ((error_bits & SYSIO_CEAFSR_PDRD) ?
@@ -360,14 +375,14 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
         * XXX UDB CE trap handler does... -DaveM
         */
        printk("SYSIO[%x]: DOFF[%lx] ECC Syndrome[%lx] Size[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_CEAFSR_DOFF) >> 45UL,
               (afsr & SYSIO_CEAFSR_ESYND) >> 48UL,
               (afsr & SYSIO_CEAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_CEAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
 
-       printk("SYSIO[%x]: Secondary CE errors [", sbus->portid);
+       printk("SYSIO[%x]: Secondary CE errors [", portid);
        reported = 0;
        if (afsr & SYSIO_CEAFSR_SPIO) {
                reported++;
@@ -404,11 +419,11 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
 #define  SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved                  */
 static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 {
-       struct sbus_bus *sbus = dev_id;
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct of_device *op = dev_id;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long afsr_reg, afar_reg, reg_base;
        unsigned long afsr, afar, error_bits;
-       int reported;
+       int reported, portid;
 
        reg_base = iommu->write_complete_reg - 0x2000UL;
        afsr_reg = reg_base + SYSIO_SBUS_AFSR;
@@ -423,9 +438,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
                 SYSIO_SBAFSR_SLE | SYSIO_SBAFSR_STO | SYSIO_SBAFSR_SBERR);
        upa_writeq(error_bits, afsr_reg);
 
+       portid = of_getintprop_default(op->node, "portid", -1);
+
        /* Log the error. */
        printk("SYSIO[%x]: SBUS Error, primary error type[%s] read(%d)\n",
-              sbus->portid,
+              portid,
               (((error_bits & SYSIO_SBAFSR_PLE) ?
                 "Late PIO Error" :
                 ((error_bits & SYSIO_SBAFSR_PTO) ?
@@ -434,11 +451,11 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
                   "Error Ack" : "???")))),
               (afsr & SYSIO_SBAFSR_RD) ? 1 : 0);
        printk("SYSIO[%x]: size[%lx] MID[%lx]\n",
-              sbus->portid,
+              portid,
               (afsr & SYSIO_SBAFSR_SIZE) >> 42UL,
               (afsr & SYSIO_SBAFSR_MID) >> 37UL);
-       printk("SYSIO[%x]: AFAR[%016lx]\n", sbus->portid, afar);
-       printk("SYSIO[%x]: Secondary SBUS errors [", sbus->portid);
+       printk("SYSIO[%x]: AFAR[%016lx]\n", portid, afar);
+       printk("SYSIO[%x]: Secondary SBUS errors [", portid);
        reported = 0;
        if (afsr & SYSIO_SBAFSR_SLE) {
                reported++;
@@ -470,34 +487,37 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
 #define SYSIO_CE_INO           0x35
 #define SYSIO_SBUSERR_INO      0x36
 
-static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
+static void __init sysio_register_error_handlers(struct of_device *op)
 {
-       struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
+       struct iommu *iommu = op->dev.archdata.iommu;
        unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
        unsigned int irq;
        u64 control;
+       int portid;
+
+       portid = of_getintprop_default(op->node, "portid", -1);
 
-       irq = sbus_build_irq(sbus, SYSIO_UE_INO);
+       irq = sbus_build_irq(op, SYSIO_UE_INO);
        if (request_irq(irq, sysio_ue_handler, 0,
-                       "SYSIO_UE", sbus) < 0) {
+                       "SYSIO_UE", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register UE interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
-       irq = sbus_build_irq(sbus, SYSIO_CE_INO);
+       irq = sbus_build_irq(op, SYSIO_CE_INO);
        if (request_irq(irq, sysio_ce_handler, 0,
-                       "SYSIO_CE", sbus) < 0) {
+                       "SYSIO_CE", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register CE interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
-       irq = sbus_build_irq(sbus, SYSIO_SBUSERR_INO);
+       irq = sbus_build_irq(op, SYSIO_SBUSERR_INO);
        if (request_irq(irq, sysio_sbus_error_handler, 0,
-                       "SYSIO_SBERR", sbus) < 0) {
+                       "SYSIO_SBERR", op) < 0) {
                prom_printf("SYSIO[%x]: Cannot register SBUS Error interrupt.\n",
-                           sbus->portid);
+                           portid);
                prom_halt();
        }
 
@@ -513,19 +533,15 @@ static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
 }
 
 /* Boot time initialization. */
-static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
+static void __init sbus_iommu_init(struct of_device *op)
 {
        const struct linux_prom64_registers *pr;
-       struct device_node *dp;
+       struct device_node *dp = op->node;
        struct iommu *iommu;
        struct strbuf *strbuf;
        unsigned long regs, reg_base;
+       int i, portid;
        u64 control;
-       int i;
-
-       dp = of_find_node_by_phandle(__node);
-
-       sbus->portid = of_getintprop_default(dp, "upa-portid", -1);
 
        pr = of_get_property(dp, "reg", NULL);
        if (!pr) {
@@ -542,9 +558,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
        if (!strbuf)
                goto fatal_memory_error;
 
-       sbus->ofdev.dev.archdata.iommu = iommu;
-       sbus->ofdev.dev.archdata.stc = strbuf;
-       sbus->ofdev.dev.archdata.numa_node = -1;
+       op->dev.archdata.iommu = iommu;
+       op->dev.archdata.stc = strbuf;
+       op->dev.archdata.numa_node = -1;
 
        reg_base = regs + SYSIO_IOMMUREG_BASE;
        iommu->iommu_control = reg_base + IOMMU_CONTROL;
@@ -572,8 +588,9 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
         */
        iommu->write_complete_reg = regs + 0x2000UL;
 
-       printk("SYSIO: UPA portID %x, at %016lx\n",
-              sbus->portid, regs);
+       portid = of_getintprop_default(op->node, "portid", -1);
+       printk(KERN_INFO "SYSIO: UPA portID %x, at %016lx\n",
+              portid, regs);
 
        /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
        if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff, -1))
@@ -631,56 +648,27 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
 
        /* Now some Xfire specific grot... */
        if (this_is_starfire)
-               starfire_hookup(sbus->portid);
+               starfire_hookup(portid);
 
-       sysio_register_error_handlers(sbus);
+       sysio_register_error_handlers(op);
        return;
 
 fatal_memory_error:
        prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
 }
 
-void sbus_fill_device_irq(struct sbus_dev *sdev)
+static int __init sbus_init(void)
 {
-       struct device_node *dp = of_find_node_by_phandle(sdev->prom_node);
-       const struct linux_prom_irqs *irqs;
-
-       irqs = of_get_property(dp, "interrupts", NULL);
-       if (!irqs) {
-               sdev->irqs[0] = 0;
-               sdev->num_irqs = 0;
-       } else {
-               unsigned int pri = irqs[0].pri;
+       struct device_node *dp;
 
-               sdev->num_irqs = 1;
-               if (pri < 0x20)
-                       pri += sdev->slot * 8;
+       for_each_node_by_name(dp, "sbus") {
+               struct of_device *op = of_find_device_by_node(dp);
 
-               sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+               sbus_iommu_init(op);
+               of_propagate_archdata(op);
        }
-}
 
-void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus)
-{
-}
-
-void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp)
-{
-       sbus_iommu_init(dp->node, sbus);
-}
-
-void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp)
-{
-}
-
-int __init sbus_arch_preinit(void)
-{
        return 0;
 }
 
-void __init sbus_arch_postinit(void)
-{
-       extern void firetruck_init(void);
-
-       firetruck_init();
-}
+subsys_initcall(sbus_init);
index 0804f71df6cb8422fd09fda447be1a397fbd3c03..30bba8b0a3b0f91dadcc2aac44b0de329e5ec430 100644 (file)
@@ -36,7 +36,6 @@
 #include <asm/elf.h>
 #include <asm/head.h>
 #include <asm/smp.h>
-#include <asm/mostek.h>
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/checksum.h>
 #include <asm/pgalloc.h>
 #include <asm/cacheflush.h>
 #ifdef CONFIG_SBUS
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
-#ifdef CONFIG_PCI
-#include <asm/ebus.h>
-#endif
 #include <asm/ns87303.h>
 #include <asm/timer.h>
 #include <asm/cpudata.h>
@@ -68,7 +63,6 @@ extern void *__memscan_zero(void *, size_t);
 extern void *__memscan_generic(void *, int, size_t);
 extern int __memcmp(const void *, const void *, __kernel_size_t);
 extern __kernel_size_t strlen(const char *);
-extern void syscall_trace(struct pt_regs *, int);
 extern void sys_sigsuspend(void);
 extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
@@ -154,26 +148,12 @@ EXPORT_SYMBOL(flush_dcache_page);
 EXPORT_SYMBOL(__flush_dcache_range);
 #endif
 
-EXPORT_SYMBOL(mostek_lock);
-EXPORT_SYMBOL(mstk48t02_regs);
 #ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
 #endif
 #ifdef CONFIG_SBUS
-EXPORT_SYMBOL(sbus_root);
-EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
-EXPORT_SYMBOL(sbus_alloc_consistent);
-EXPORT_SYMBOL(sbus_free_consistent);
-EXPORT_SYMBOL(sbus_map_single);
-EXPORT_SYMBOL(sbus_unmap_single);
-EXPORT_SYMBOL(sbus_map_sg);
-EXPORT_SYMBOL(sbus_unmap_sg);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_single_for_device);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu);
-EXPORT_SYMBOL(sbus_dma_sync_sg_for_device);
 #endif
 EXPORT_SYMBOL(outsb);
 EXPORT_SYMBOL(outsw);
@@ -182,7 +162,6 @@ EXPORT_SYMBOL(insb);
 EXPORT_SYMBOL(insw);
 EXPORT_SYMBOL(insl);
 #ifdef CONFIG_PCI
-EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(pci_alloc_consistent);
 EXPORT_SYMBOL(pci_free_consistent);
 EXPORT_SYMBOL(pci_map_single);
@@ -300,3 +279,5 @@ EXPORT_SYMBOL(xor_niagara_2);
 EXPORT_SYMBOL(xor_niagara_3);
 EXPORT_SYMBOL(xor_niagara_4);
 EXPORT_SYMBOL(xor_niagara_5);
+
+EXPORT_SYMBOL_GPL(real_hard_smp_processor_id);
index 5b6e75b7f0526dadf4935ace3ed23d0f2353a834..8cdbe5946b43eb6afde994aea6e36e47c58f51b6 100644 (file)
@@ -1,14 +1,15 @@
 /* sstate.c: System soft state support.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/kernel.h>
 #include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 
 #include <asm/hypervisor.h>
-#include <asm/sstate.h>
+#include <asm/spitfire.h>
 #include <asm/oplib.h>
 #include <asm/head.h>
 #include <asm/io.h>
@@ -50,31 +51,34 @@ static const char rebooting_msg[32] __attribute__((aligned(32))) =
 static const char panicing_msg[32] __attribute__((aligned(32))) =
        "Linux panicing";
 
-void sstate_booting(void)
+static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
 {
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
-}
+       const char *msg;
 
-void sstate_running(void)
-{
-       do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
-}
+       switch (type) {
+       case SYS_DOWN:
+       default:
+               msg = rebooting_msg;
+               break;
 
-void sstate_halt(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, halting_msg);
-}
+       case SYS_HALT:
+               msg = halting_msg;
+               break;
 
-void sstate_poweroff(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, poweroff_msg);
-}
+       case SYS_POWER_OFF:
+               msg = poweroff_msg;
+               break;
+       }
 
-void sstate_reboot(void)
-{
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, rebooting_msg);
+       do_set_sstate(HV_SOFT_STATE_TRANSITION, msg);
+
+       return NOTIFY_OK;
 }
 
+static struct notifier_block sstate_reboot_notifier = {
+       .notifier_call = sstate_reboot_call,
+};
+
 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
 {
        do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
@@ -87,18 +91,37 @@ static struct notifier_block sstate_panic_block = {
        .priority       =       INT_MAX,
 };
 
-void __init sun4v_sstate_init(void)
+static int __init sstate_init(void)
 {
        unsigned long major, minor;
 
+       if (tlb_type != hypervisor)
+               return 0;
+
        major = 1;
        minor = 0;
        if (sun4v_hvapi_register(HV_GRP_SOFT_STATE, major, &minor))
-               return;
+               return 0;
 
        hv_supports_soft_state = 1;
 
        prom_sun4v_guest_soft_state();
+
+       do_set_sstate(HV_SOFT_STATE_TRANSITION, booting_msg);
+
        atomic_notifier_chain_register(&panic_notifier_list,
                                       &sstate_panic_block);
+       register_reboot_notifier(&sstate_reboot_notifier);
+
+       return 0;
 }
+
+core_initcall(sstate_init);
+
+static int __init sstate_running(void)
+{
+       do_set_sstate(HV_SOFT_STATE_NORMAL, running_msg);
+       return 0;
+}
+
+late_initcall(sstate_running);
index 7461581b3bb972c29ab0f6e6ce7facbb7d132d89..060d0f3a61511ee2b1891837ea4de94ca398d69c 100644 (file)
@@ -28,11 +28,6 @@ void check_if_starfire(void)
                this_is_starfire = 1;
 }
 
-void starfire_cpu_setup(void)
-{
-       /* Currently, nothing to do.  */
-}
-
 int starfire_hard_smp_processor_id(void)
 {
        return upa_readl(0x1fff40000d0UL);
index 3d118531baffab98e1dea2f1e414bae47674791b..3320c9d0075f79eac52690def1371024d1b3f9bb 100644 (file)
@@ -575,14 +575,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
        return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
 }
 
-/* These are here just in case some old sparc32 binary calls it. */
-asmlinkage long sys32_pause(void)
-{
-       current->state = TASK_INTERRUPTIBLE;
-       schedule();
-       return -ERESTARTNOHAND;
-}
-
 asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
                                        char __user *ubuf,
                                        compat_size_t count,
index a2f24270ed8af9f95b95ee0f685419b621244fa2..7a6786a71363c71f64e6686b31adb50f0faa1175 100644 (file)
@@ -65,9 +65,8 @@ sys32_rt_sigreturn:
        andcc   %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
        be,pt   %icc, rtrap
         nop
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        mov    1, %o1
+       call    syscall_trace_leave
+        add    %sp, PTREGS_OFF, %o0
        ba,pt   %xcc, rtrap
         nop
 
@@ -159,9 +158,8 @@ linux_sparc_ni_syscall:
         or     %l7, %lo(sys_ni_syscall), %l7
 
 linux_syscall_trace32:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        clr    %o1
+       call    syscall_trace_enter
+        add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
        srl     %i0, 0, %o0
@@ -172,9 +170,8 @@ linux_syscall_trace32:
         srl    %i3, 0, %o3
 
 linux_syscall_trace:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        clr    %o1
+       call    syscall_trace_enter
+        add    %sp, PTREGS_OFF, %o0
        brnz,pn %o0, 3f
         mov    -ENOSYS, %o0
        mov     %i0, %o0
@@ -275,9 +272,8 @@ ret_sys_call:
        b,pt    %xcc, rtrap
         stx    %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
 linux_syscall_trace2:
-       add     %sp, PTREGS_OFF, %o0
-       call    syscall_trace
-        mov    1, %o1
+       call    syscall_trace_leave
+        add    %sp, PTREGS_OFF, %o0
        stx     %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
        ba,pt   %xcc, rtrap
         stx    %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
index 0fdbf3ba956ee9c8f4d1e7586a174f80cf733e92..5daee4b04dd5a655c313c07ee1dabf4ea34871fe 100644 (file)
@@ -23,7 +23,7 @@ sys_call_table32:
 /*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod
 /*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek
 /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16
-/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
+/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause
 /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice
        .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile
 /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid
index cc16fdcf98af1a84c81126525a974ce81bbffc74..80d71a5ce1e3ab414cc81cda2eb6bf63973ef368 100644 (file)
 #include <linux/percpu.h>
 #include <linux/miscdevice.h>
 #include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
 #include <linux/kernel_stat.h>
 #include <linux/clockchips.h>
 #include <linux/clocksource.h>
 #include <linux/of_device.h>
+#include <linux/platform_device.h>
 
 #include <asm/oplib.h>
-#include <asm/mostek.h>
 #include <asm/timer.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
 #include "entry.h"
 
-DEFINE_SPINLOCK(mostek_lock);
 DEFINE_SPINLOCK(rtc_lock);
-void __iomem *mstk48t02_regs = NULL;
-#ifdef CONFIG_PCI
-unsigned long ds1287_regs = 0UL;
-static void __iomem *bq4802_regs;
-#endif
-
-static void __iomem *mstk48t08_regs;
-static void __iomem *mstk48t59_regs;
-
-static int set_rtc_mmss(unsigned long);
 
 #define TICK_PRIV_BIT  (1UL << 63)
 #define TICKCMP_IRQ_BIT        (1UL << 63)
@@ -405,313 +395,167 @@ static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
 
 int update_persistent_clock(struct timespec now)
 {
-       return set_rtc_mmss(now.tv_sec);
-}
+       struct rtc_device *rtc = rtc_class_open("rtc0");
+       int err = -1;
 
-/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
-static void __init kick_start_clock(void)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 sec, tmp;
-       int i, count;
-
-       prom_printf("CLOCK: Clock was stopped. Kick start ");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn on the kick start bit to start the oscillator. */
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-       tmp = mostek_read(regs + MOSTEK_SEC);
-       tmp &= ~MSTK_STOP;
-       mostek_write(regs + MOSTEK_SEC, tmp);
-       tmp = mostek_read(regs + MOSTEK_HOUR);
-       tmp |= MSTK_KICK_START;
-       mostek_write(regs + MOSTEK_HOUR, tmp);
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Delay to allow the clock oscillator to start. */
-       sec = MSTK_REG_SEC(regs);
-       for (i = 0; i < 3; i++) {
-               while (sec == MSTK_REG_SEC(regs))
-                       for (count = 0; count < 100000; count++)
-                               /* nothing */ ;
-               prom_printf(".");
-               sec = MSTK_REG_SEC(regs);
-       }
-       prom_printf("\n");
-
-       spin_lock_irq(&mostek_lock);
-
-       /* Turn off kick start and set a "valid" time and date. */
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-       tmp = mostek_read(regs + MOSTEK_HOUR);
-       tmp &= ~MSTK_KICK_START;
-       mostek_write(regs + MOSTEK_HOUR, tmp);
-       MSTK_SET_REG_SEC(regs,0);
-       MSTK_SET_REG_MIN(regs,0);
-       MSTK_SET_REG_HOUR(regs,0);
-       MSTK_SET_REG_DOW(regs,5);
-       MSTK_SET_REG_DOM(regs,1);
-       MSTK_SET_REG_MONTH(regs,8);
-       MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       /* Ensure the kick start bit is off. If it isn't, turn it off. */
-       while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {
-               prom_printf("CLOCK: Kick start still on!\n");
-
-               spin_lock_irq(&mostek_lock);
-
-               tmp = mostek_read(regs + MOSTEK_CREG);
-               tmp |= MSTK_CREG_WRITE;
-               mostek_write(regs + MOSTEK_CREG, tmp);
-
-               tmp = mostek_read(regs + MOSTEK_HOUR);
-               tmp &= ~MSTK_KICK_START;
-               mostek_write(regs + MOSTEK_HOUR, tmp);
-
-               tmp = mostek_read(regs + MOSTEK_CREG);
-               tmp &= ~MSTK_CREG_WRITE;
-               mostek_write(regs + MOSTEK_CREG, tmp);
-
-               spin_unlock_irq(&mostek_lock);
+       if (rtc) {
+               err = rtc_set_mmss(rtc, now.tv_sec);
+               rtc_class_close(rtc);
        }
 
-       prom_printf("CLOCK: Kick start procedure successful.\n");
+       return err;
 }
 
-/* Return nonzero if the clock chip battery is low. */
-static int __init has_low_battery(void)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 data1, data2;
-
-       spin_lock_irq(&mostek_lock);
+unsigned long cmos_regs;
+EXPORT_SYMBOL(cmos_regs);
 
-       data1 = mostek_read(regs + MOSTEK_EEPROM);      /* Read some data. */
-       mostek_write(regs + MOSTEK_EEPROM, ~data1);     /* Write back the complement. */
-       data2 = mostek_read(regs + MOSTEK_EEPROM);      /* Read back the complement. */
-       mostek_write(regs + MOSTEK_EEPROM, data1);      /* Restore original value. */
+static struct resource rtc_cmos_resource;
 
-       spin_unlock_irq(&mostek_lock);
-
-       return (data1 == data2);        /* Was the write blocked? */
-}
+static struct platform_device rtc_cmos_device = {
+       .name           = "rtc_cmos",
+       .id             = -1,
+       .resource       = &rtc_cmos_resource,
+       .num_resources  = 1,
+};
 
-static void __init mostek_set_system_time(void __iomem *mregs)
+static int __devinit rtc_probe(struct of_device *op, const struct of_device_id *match)
 {
-       unsigned int year, mon, day, hour, min, sec;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
+       struct resource *r;
 
-       /* Traditional Mostek chip. */
-       tmp = mostek_read(mregs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(mregs + MOSTEK_CREG, tmp);
+       printk(KERN_INFO "%s: RTC regs at 0x%lx\n",
+              op->node->full_name, op->resource[0].start);
 
-       sec = MSTK_REG_SEC(mregs);
-       min = MSTK_REG_MIN(mregs);
-       hour = MSTK_REG_HOUR(mregs);
-       day = MSTK_REG_DOM(mregs);
-       mon = MSTK_REG_MONTH(mregs);
-       year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
-
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
+       /* The CMOS RTC driver only accepts IORESOURCE_IO, so cons
+        * up a fake resource so that the probe works for all cases.
+        * When the RTC is behind an ISA bus it will have IORESOURCE_IO
+        * already, whereas when it's behind EBUS is will be IORESOURCE_MEM.
+        */
 
-       tmp = mostek_read(mregs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(mregs + MOSTEK_CREG, tmp);
+       r = &rtc_cmos_resource;
+       r->flags = IORESOURCE_IO;
+       r->name = op->resource[0].name;
+       r->start = op->resource[0].start;
+       r->end = op->resource[0].end;
 
-       spin_unlock_irq(&mostek_lock);
+       cmos_regs = op->resource[0].start;
+       return platform_device_register(&rtc_cmos_device);
 }
 
-/* Probe for the real time clock chip. */
-static void __init set_system_time(void)
-{
-       unsigned int year, mon, day, hour, min, sec;
-       void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-       unsigned long dregs = ds1287_regs;
-       void __iomem *bregs = bq4802_regs;
-#else
-       unsigned long dregs = 0UL;
-       void __iomem *bregs = 0UL;
-#endif
-
-       if (!mregs && !dregs && !bregs) {
-               prom_printf("Something wrong, clock regs not mapped yet.\n");
-               prom_halt();
-       }               
-
-       if (mregs) {
-               mostek_set_system_time(mregs);
-               return;
-       }
-
-       if (bregs) {
-               unsigned char val = readb(bregs + 0x0e);
-               unsigned int century;
+static struct of_device_id __initdata rtc_match[] = {
+       {
+               .name = "rtc",
+               .compatible = "m5819",
+       },
+       {
+               .name = "rtc",
+               .compatible = "isa-m5819p",
+       },
+       {
+               .name = "rtc",
+               .compatible = "isa-m5823p",
+       },
+       {
+               .name = "rtc",
+               .compatible = "ds1287",
+       },
+       {},
+};
 
-               /* BQ4802 RTC chip. */
+static struct of_platform_driver rtc_driver = {
+       .match_table    = rtc_match,
+       .probe          = rtc_probe,
+       .driver         = {
+               .name   = "rtc",
+       },
+};
 
-               writeb(val | 0x08, bregs + 0x0e);
+static struct platform_device rtc_bq4802_device = {
+       .name           = "rtc-bq4802",
+       .id             = -1,
+       .num_resources  = 1,
+};
 
-               sec  = readb(bregs + 0x00);
-               min  = readb(bregs + 0x02);
-               hour = readb(bregs + 0x04);
-               day  = readb(bregs + 0x06);
-               mon  = readb(bregs + 0x09);
-               year = readb(bregs + 0x0a);
-               century = readb(bregs + 0x0f);
+static int __devinit bq4802_probe(struct of_device *op, const struct of_device_id *match)
+{
 
-               writeb(val, bregs + 0x0e);
+       printk(KERN_INFO "%s: BQ4802 regs at 0x%lx\n",
+              op->node->full_name, op->resource[0].start);
 
-               BCD_TO_BIN(sec);
-               BCD_TO_BIN(min);
-               BCD_TO_BIN(hour);
-               BCD_TO_BIN(day);
-               BCD_TO_BIN(mon);
-               BCD_TO_BIN(year);
-               BCD_TO_BIN(century);
+       rtc_bq4802_device.resource = &op->resource[0];
+       return platform_device_register(&rtc_bq4802_device);
+}
 
-               year += (century * 100);
-       } else {
-               /* Dallas 12887 RTC chip. */
-
-               do {
-                       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));
-
-               if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-                       BCD_TO_BIN(sec);
-                       BCD_TO_BIN(min);
-                       BCD_TO_BIN(hour);
-                       BCD_TO_BIN(day);
-                       BCD_TO_BIN(mon);
-                       BCD_TO_BIN(year);
-               }
-               if ((year += 1900) < 1970)
-                       year += 100;
-       }
+static struct of_device_id __initdata bq4802_match[] = {
+       {
+               .name = "rtc",
+               .compatible = "bq4802",
+       },
+};
 
-       xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
-       xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
-}
+static struct of_platform_driver bq4802_driver = {
+       .match_table    = bq4802_match,
+       .probe          = bq4802_probe,
+       .driver         = {
+               .name   = "bq4802",
+       },
+};
 
-/* davem suggests we keep this within the 4M locked kernel image */
-static u32 starfire_get_time(void)
+static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
 {
-       static char obp_gettod[32];
-       static u32 unix_tod;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs;
+       unsigned char val;
 
-       sprintf(obp_gettod, "h# %08x unix-gettod",
-               (unsigned int) (long) &unix_tod);
-       prom_feval(obp_gettod);
+       regs = (void __iomem *) pdev->resource[0].start;
+       val = readb(regs + ofs);
 
-       return unix_tod;
+       /* the year 0 is 1968 */
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               val += 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+       }
+       return val;
 }
 
-static int starfire_set_time(u32 val)
+static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
 {
-       /* Do nothing, time is set using the service processor
-        * console on this platform.
-        */
-       return 0;
-}
+       struct platform_device *pdev = to_platform_device(dev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+       void __iomem *regs;
 
-static u32 hypervisor_get_time(void)
-{
-       unsigned long ret, time;
-       int retries = 10000;
-
-retry:
-       ret = sun4v_tod_get(&time);
-       if (ret == HV_EOK)
-               return time;
-       if (ret == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
-               return 0;
+       regs = (void __iomem *) pdev->resource[0].start;
+       if (ofs == pdata->offset + M48T59_YEAR) {
+               if (val < 0x68)
+                       val += 0x32;
+               else
+                       val -= 0x68;
+               if ((val & 0xf) > 9)
+                       val += 6;
+               if ((val & 0xf0) > 0x9A)
+                       val += 0x60;
        }
-       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
-       return 0;
+       writeb(val, regs + ofs);
 }
 
-static int hypervisor_set_time(u32 secs)
-{
-       unsigned long ret;
-       int retries = 10000;
-
-retry:
-       ret = sun4v_tod_set(secs);
-       if (ret == HV_EOK)
-               return 0;
-       if (ret == HV_EWOULDBLOCK) {
-               if (--retries > 0) {
-                       udelay(100);
-                       goto retry;
-               }
-               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
-               return -EAGAIN;
-       }
-       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
-       return -EOPNOTSUPP;
-}
+static struct m48t59_plat_data m48t59_data = {
+       .read_byte      = mostek_read_byte,
+       .write_byte     = mostek_write_byte,
+};
 
-static int __init clock_model_matches(const char *model)
-{
-       if (strcmp(model, "mk48t02") &&
-           strcmp(model, "mk48t08") &&
-           strcmp(model, "mk48t59") &&
-           strcmp(model, "m5819") &&
-           strcmp(model, "m5819p") &&
-           strcmp(model, "m5823") &&
-           strcmp(model, "ds1287") &&
-           strcmp(model, "bq4802"))
-               return 0;
-
-       return 1;
-}
+static struct platform_device m48t59_rtc = {
+       .name           = "rtc-m48t59",
+       .id             = 0,
+       .num_resources  = 1,
+       .dev    = {
+               .platform_data = &m48t59_data,
+       },
+};
 
-static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
+static int __devinit mostek_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
-       const char *model = of_get_property(dp, "model", NULL);
-       const char *compat = of_get_property(dp, "compatible", NULL);
-       unsigned long size, flags;
-       void __iomem *regs;
-
-       if (!model)
-               model = compat;
-
-       if (!model || !clock_model_matches(model))
-               return -ENODEV;
 
        /* On an Enterprise system there can be multiple mostek clocks.
         * We should only match the one that is on the central FHC bus.
@@ -720,88 +564,51 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
            strcmp(dp->parent->parent->name, "central") != 0)
                return -ENODEV;
 
-       size = (op->resource[0].end - op->resource[0].start) + 1;
-       regs = of_ioremap(&op->resource[0], 0, size, "clock");
-       if (!regs)
-               return -ENOMEM;
-
-#ifdef CONFIG_PCI
-       if (!strcmp(model, "ds1287") ||
-           !strcmp(model, "m5819") ||
-           !strcmp(model, "m5819p") ||
-           !strcmp(model, "m5823")) {
-               ds1287_regs = (unsigned long) regs;
-       } else if (!strcmp(model, "bq4802")) {
-               bq4802_regs = regs;
-       } else
-#endif
-       if (model[5] == '0' && model[6] == '2') {
-               mstk48t02_regs = regs;
-       } else if(model[5] == '0' && model[6] == '8') {
-               mstk48t08_regs = regs;
-               mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02;
-       } else {
-               mstk48t59_regs = regs;
-               mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02;
-       }
-
-       printk(KERN_INFO "%s: Clock regs at %p\n", dp->full_name, regs);
-
-       local_irq_save(flags);
-
-       if (mstk48t02_regs != NULL) {
-               /* Report a low battery voltage condition. */
-               if (has_low_battery())
-                       prom_printf("NVRAM: Low battery voltage!\n");
-
-               /* Kick start the clock if it is completely stopped. */
-               if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
-                       kick_start_clock();
-       }
-
-       set_system_time();
-       
-       local_irq_restore(flags);
+       printk(KERN_INFO "%s: Mostek regs at 0x%lx\n",
+              dp->full_name, op->resource[0].start);
 
-       return 0;
+       m48t59_rtc.resource = &op->resource[0];
+       return platform_device_register(&m48t59_rtc);
 }
 
-static struct of_device_id clock_match[] = {
+static struct of_device_id __initdata mostek_match[] = {
        {
                .name = "eeprom",
        },
-       {
-               .name = "rtc",
-       },
        {},
 };
 
-static struct of_platform_driver clock_driver = {
-       .match_table    = clock_match,
-       .probe          = clock_probe,
+static struct of_platform_driver mostek_driver = {
+       .match_table    = mostek_match,
+       .probe          = mostek_probe,
        .driver         = {
-               .name   = "clock",
+               .name   = "mostek",
        },
 };
 
+static struct platform_device rtc_sun4v_device = {
+       .name           = "rtc-sun4v",
+       .id             = -1,
+};
+
+static struct platform_device rtc_starfire_device = {
+       .name           = "rtc-starfire",
+       .id             = -1,
+};
+
 static int __init clock_init(void)
 {
-       if (this_is_starfire) {
-               xtime.tv_sec = starfire_get_time();
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                       -xtime.tv_sec, -xtime.tv_nsec);
-               return 0;
-       }
-       if (tlb_type == hypervisor) {
-               xtime.tv_sec = hypervisor_get_time();
-               xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
-               set_normalized_timespec(&wall_to_monotonic,
-                                       -xtime.tv_sec, -xtime.tv_nsec);
-               return 0;
-       }
+       if (this_is_starfire)
+               return platform_device_register(&rtc_starfire_device);
+
+       if (tlb_type == hypervisor)
+               return platform_device_register(&rtc_sun4v_device);
+
+       (void) of_register_driver(&rtc_driver, &of_platform_bus_type);
+       (void) of_register_driver(&mostek_driver, &of_platform_bus_type);
+       (void) of_register_driver(&bq4802_driver, &of_platform_bus_type);
 
-       return of_register_driver(&clock_driver, &of_platform_bus_type);
+       return 0;
 }
 
 /* Must be after subsys_initcall() so that busses are probed.  Must
@@ -814,7 +621,7 @@ fs_initcall(clock_init);
 static unsigned long sparc64_init_timers(void)
 {
        struct device_node *dp;
-       unsigned long clock;
+       unsigned long freq;
 
        dp = of_find_node_by_path("/");
        if (tlb_type == spitfire) {
@@ -827,17 +634,17 @@ static unsigned long sparc64_init_timers(void)
                if (manuf == 0x17 && impl == 0x13) {
                        /* Hummingbird, aka Ultra-IIe */
                        tick_ops = &hbtick_operations;
-                       clock = of_getintprop_default(dp, "stick-frequency", 0);
+                       freq = of_getintprop_default(dp, "stick-frequency", 0);
                } else {
                        tick_ops = &tick_operations;
-                       clock = local_cpu_data().clock_tick;
+                       freq = local_cpu_data().clock_tick;
                }
        } else {
                tick_ops = &stick_operations;
-               clock = of_getintprop_default(dp, "stick-frequency", 0);
+               freq = of_getintprop_default(dp, "stick-frequency", 0);
        }
 
-       return clock;
+       return freq;
 }
 
 struct freq_table {
@@ -1029,16 +836,16 @@ EXPORT_SYMBOL(udelay);
 
 void __init time_init(void)
 {
-       unsigned long clock = sparc64_init_timers();
+       unsigned long freq = sparc64_init_timers();
 
-       tb_ticks_per_usec = clock / USEC_PER_SEC;
+       tb_ticks_per_usec = freq / USEC_PER_SEC;
 
        timer_ticks_per_nsec_quotient =
-               clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
+               clocksource_hz2mult(freq, SPARC64_NSEC_PER_CYC_SHIFT);
 
        clocksource_tick.name = tick_ops->name;
        clocksource_tick.mult =
-               clocksource_hz2mult(clock,
+               clocksource_hz2mult(freq,
                                    clocksource_tick.shift);
        clocksource_tick.read = tick_ops->get_tick;
 
@@ -1049,7 +856,7 @@ void __init time_init(void)
 
        sparc64_clockevent.name = tick_ops->name;
 
-       setup_clockevent_multiplier(clock);
+       setup_clockevent_multiplier(freq);
 
        sparc64_clockevent.max_delta_ns =
                clockevent_delta2ns(0x7fffffffffffffffUL, &sparc64_clockevent);
@@ -1070,672 +877,8 @@ unsigned long long sched_clock(void)
                >> SPARC64_NSEC_PER_CYC_SHIFT;
 }
 
-static int set_rtc_mmss(unsigned long nowtime)
-{
-       int real_seconds, real_minutes, chip_minutes;
-       void __iomem *mregs = mstk48t02_regs;
-#ifdef CONFIG_PCI
-       unsigned long dregs = ds1287_regs;
-       void __iomem *bregs = bq4802_regs;
-#else
-       unsigned long dregs = 0UL;
-       void __iomem *bregs = 0UL;
-#endif
-       unsigned long flags;
-       u8 tmp;
-
-       /* 
-        * Not having a register set can lead to trouble.
-        * Also starfire doesn't have a tod clock.
-        */
-       if (!mregs && !dregs && !bregs)
-               return -1;
-
-       if (mregs) {
-               spin_lock_irqsave(&mostek_lock, flags);
-
-               /* Read the current RTC minutes. */
-               tmp = mostek_read(mregs + MOSTEK_CREG);
-               tmp |= MSTK_CREG_READ;
-               mostek_write(mregs + MOSTEK_CREG, tmp);
-
-               chip_minutes = MSTK_REG_MIN(mregs);
-
-               tmp = mostek_read(mregs + MOSTEK_CREG);
-               tmp &= ~MSTK_CREG_READ;
-               mostek_write(mregs + MOSTEK_CREG, tmp);
-
-               /*
-                * since we're only adjusting minutes and seconds,
-                * don't interfere with hour overflow. This avoids
-                * messing with unknown time zones but requires your
-                * RTC not to be off by more than 15 minutes
-                */
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;     /* correct for half hour time zone */
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       tmp = mostek_read(mregs + MOSTEK_CREG);
-                       tmp |= MSTK_CREG_WRITE;
-                       mostek_write(mregs + MOSTEK_CREG, tmp);
-
-                       MSTK_SET_REG_SEC(mregs,real_seconds);
-                       MSTK_SET_REG_MIN(mregs,real_minutes);
-
-                       tmp = mostek_read(mregs + MOSTEK_CREG);
-                       tmp &= ~MSTK_CREG_WRITE;
-                       mostek_write(mregs + MOSTEK_CREG, tmp);
-
-                       spin_unlock_irqrestore(&mostek_lock, flags);
-
-                       return 0;
-               } else {
-                       spin_unlock_irqrestore(&mostek_lock, flags);
-
-                       return -1;
-               }
-       } else if (bregs) {
-               int retval = 0;
-               unsigned char val = readb(bregs + 0x0e);
-
-               /* BQ4802 RTC chip. */
-
-               writeb(val | 0x08, bregs + 0x0e);
-
-               chip_minutes = readb(bregs + 0x02);
-               BCD_TO_BIN(chip_minutes);
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       BIN_TO_BCD(real_seconds);
-                       BIN_TO_BCD(real_minutes);
-                       writeb(real_seconds, bregs + 0x00);
-                       writeb(real_minutes, bregs + 0x02);
-               } else {
-                       printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                              chip_minutes, real_minutes);
-                       retval = -1;
-               }
-
-               writeb(val, bregs + 0x0e);
-
-               return retval;
-       } else {
-               int retval = 0;
-               unsigned char save_control, save_freq_select;
-
-               /* Stolen from arch/i386/kernel/time.c, see there for
-                * credits and descriptive comments.
-                */
-               spin_lock_irqsave(&rtc_lock, flags);
-               save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
-               CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-
-               save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
-               CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-               chip_minutes = CMOS_READ(RTC_MINUTES);
-               if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
-                       BCD_TO_BIN(chip_minutes);
-               real_seconds = nowtime % 60;
-               real_minutes = nowtime / 60;
-               if (((abs(real_minutes - chip_minutes) + 15)/30) & 1)
-                       real_minutes += 30;
-               real_minutes %= 60;
-
-               if (abs(real_minutes - chip_minutes) < 30) {
-                       if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-                               BIN_TO_BCD(real_seconds);
-                               BIN_TO_BCD(real_minutes);
-                       }
-                       CMOS_WRITE(real_seconds,RTC_SECONDS);
-                       CMOS_WRITE(real_minutes,RTC_MINUTES);
-               } else {
-                       printk(KERN_WARNING
-                              "set_rtc_mmss: can't update from %d to %d\n",
-                              chip_minutes, real_minutes);
-                       retval = -1;
-               }
-
-               CMOS_WRITE(save_control, RTC_CONTROL);
-               CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-               spin_unlock_irqrestore(&rtc_lock, flags);
-
-               return retval;
-       }
-}
-
-#define RTC_IS_OPEN            0x01    /* means /dev/rtc is in use     */
-static unsigned char mini_rtc_status;  /* bitmapped status byte.       */
-
-#define FEBRUARY       2
-#define        STARTOFTIME     1970
-#define SECDAY         86400L
-#define SECYR          (SECDAY * 365)
-#define        leapyear(year)          ((year) % 4 == 0 && \
-                                ((year) % 100 != 0 || (year) % 400 == 0))
-#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
-#define        days_in_month(a)        (month_days[(a) - 1])
-
-static int month_days[12] = {
-       31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-/*
- * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
- */
-static void GregorianDay(struct rtc_time * tm)
-{
-       int leapsToDate;
-       int lastYear;
-       int day;
-       int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
-
-       lastYear = tm->tm_year - 1;
-
-       /*
-        * Number of leap corrections to apply up to end of last year
-        */
-       leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
-
-       /*
-        * This year is a leap year if it is divisible by 4 except when it is
-        * divisible by 100 unless it is divisible by 400
-        *
-        * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
-        */
-       day = tm->tm_mon > 2 && leapyear(tm->tm_year);
-
-       day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
-                  tm->tm_mday;
-
-       tm->tm_wday = day % 7;
-}
-
-static void to_tm(int tim, struct rtc_time *tm)
-{
-       register int    i;
-       register long   hms, day;
-
-       day = tim / SECDAY;
-       hms = tim % SECDAY;
-
-       /* Hours, minutes, seconds are easy */
-       tm->tm_hour = hms / 3600;
-       tm->tm_min = (hms % 3600) / 60;
-       tm->tm_sec = (hms % 3600) % 60;
-
-       /* Number of years in days */
-       for (i = STARTOFTIME; day >= days_in_year(i); i++)
-               day -= days_in_year(i);
-       tm->tm_year = i;
-
-       /* Number of months in days left */
-       if (leapyear(tm->tm_year))
-               days_in_month(FEBRUARY) = 29;
-       for (i = 1; day >= days_in_month(i); i++)
-               day -= days_in_month(i);
-       days_in_month(FEBRUARY) = 28;
-       tm->tm_mon = i;
-
-       /* Days are what is left over (+1) from all that. */
-       tm->tm_mday = day + 1;
-
-       /*
-        * Determine the day of week
-        */
-       GregorianDay(tm);
-}
-
-/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
- * aka Unix time.  So we have to convert to/from rtc_time.
- */
-static void starfire_get_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = starfire_get_time();
-
-       to_tm(seconds, time);
-       time->tm_year -= 1900;
-       time->tm_mon -= 1;
-}
-
-static int starfire_set_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-                            time->tm_mday, time->tm_hour,
-                            time->tm_min, time->tm_sec);
-
-       return starfire_set_time(seconds);
-}
-
-static void hypervisor_get_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = hypervisor_get_time();
-
-       to_tm(seconds, time);
-       time->tm_year -= 1900;
-       time->tm_mon -= 1;
-}
-
-static int hypervisor_set_rtc_time(struct rtc_time *time)
-{
-       u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
-                            time->tm_mday, time->tm_hour,
-                            time->tm_min, time->tm_sec);
-
-       return hypervisor_set_time(seconds);
-}
-
-#ifdef CONFIG_PCI
-static void bq4802_get_rtc_time(struct rtc_time *time)
-{
-       unsigned char val = readb(bq4802_regs + 0x0e);
-       unsigned int century;
-
-       writeb(val | 0x08, bq4802_regs + 0x0e);
-
-       time->tm_sec = readb(bq4802_regs + 0x00);
-       time->tm_min = readb(bq4802_regs + 0x02);
-       time->tm_hour = readb(bq4802_regs + 0x04);
-       time->tm_mday = readb(bq4802_regs + 0x06);
-       time->tm_mon = readb(bq4802_regs + 0x09);
-       time->tm_year = readb(bq4802_regs + 0x0a);
-       time->tm_wday = readb(bq4802_regs + 0x08);
-       century = readb(bq4802_regs + 0x0f);
-
-       writeb(val, bq4802_regs + 0x0e);
-
-       BCD_TO_BIN(time->tm_sec);
-       BCD_TO_BIN(time->tm_min);
-       BCD_TO_BIN(time->tm_hour);
-       BCD_TO_BIN(time->tm_mday);
-       BCD_TO_BIN(time->tm_mon);
-       BCD_TO_BIN(time->tm_year);
-       BCD_TO_BIN(time->tm_wday);
-       BCD_TO_BIN(century);
-
-       time->tm_year += (century * 100);
-       time->tm_year -= 1900;
-
-       time->tm_mon--;
-}
-
-static int bq4802_set_rtc_time(struct rtc_time *time)
-{
-       unsigned char val = readb(bq4802_regs + 0x0e);
-       unsigned char sec, min, hrs, day, mon, yrs, century;
-       unsigned int year;
-
-       year = time->tm_year + 1900;
-       century = year / 100;
-       yrs = year % 100;
-
-       mon = time->tm_mon + 1;   /* tm_mon starts at zero */
-       day = time->tm_mday;
-       hrs = time->tm_hour;
-       min = time->tm_min;
-       sec = time->tm_sec;
-
-       BIN_TO_BCD(sec);
-       BIN_TO_BCD(min);
-       BIN_TO_BCD(hrs);
-       BIN_TO_BCD(day);
-       BIN_TO_BCD(mon);
-       BIN_TO_BCD(yrs);
-       BIN_TO_BCD(century);
-
-       writeb(val | 0x08, bq4802_regs + 0x0e);
-
-       writeb(sec, bq4802_regs + 0x00);
-       writeb(min, bq4802_regs + 0x02);
-       writeb(hrs, bq4802_regs + 0x04);
-       writeb(day, bq4802_regs + 0x06);
-       writeb(mon, bq4802_regs + 0x09);
-       writeb(yrs, bq4802_regs + 0x0a);
-       writeb(century, bq4802_regs + 0x0f);
-
-       writeb(val, bq4802_regs + 0x0e);
-
-       return 0;
-}
-
-static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char ctrl;
-
-       rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
-       rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
-       rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
-       rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
-       rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
-       rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
-       rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
-
-       ctrl = CMOS_READ(RTC_CONTROL);
-       if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BCD_TO_BIN(rtc_tm->tm_sec);
-               BCD_TO_BIN(rtc_tm->tm_min);
-               BCD_TO_BIN(rtc_tm->tm_hour);
-               BCD_TO_BIN(rtc_tm->tm_mday);
-               BCD_TO_BIN(rtc_tm->tm_mon);
-               BCD_TO_BIN(rtc_tm->tm_year);
-               BCD_TO_BIN(rtc_tm->tm_wday);
-       }
-
-       if (rtc_tm->tm_year <= 69)
-               rtc_tm->tm_year += 100;
-
-       rtc_tm->tm_mon--;
-}
-
-static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char mon, day, hrs, min, sec;
-       unsigned char save_control, save_freq_select;
-       unsigned int yrs;
-
-       yrs = rtc_tm->tm_year;
-       mon = rtc_tm->tm_mon + 1;
-       day = rtc_tm->tm_mday;
-       hrs = rtc_tm->tm_hour;
-       min = rtc_tm->tm_min;
-       sec = rtc_tm->tm_sec;
-
-       if (yrs >= 100)
-               yrs -= 100;
-
-       if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-               BIN_TO_BCD(sec);
-               BIN_TO_BCD(min);
-               BIN_TO_BCD(hrs);
-               BIN_TO_BCD(day);
-               BIN_TO_BCD(mon);
-               BIN_TO_BCD(yrs);
-       }
-
-       save_control = CMOS_READ(RTC_CONTROL);
-       CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
-       save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
-       CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
-
-       CMOS_WRITE(yrs, RTC_YEAR);
-       CMOS_WRITE(mon, RTC_MONTH);
-       CMOS_WRITE(day, RTC_DAY_OF_MONTH);
-       CMOS_WRITE(hrs, RTC_HOURS);
-       CMOS_WRITE(min, RTC_MINUTES);
-       CMOS_WRITE(sec, RTC_SECONDS);
-
-       CMOS_WRITE(save_control, RTC_CONTROL);
-       CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
-
-       return 0;
-}
-#endif /* CONFIG_PCI */
-
-static void mostek_get_rtc_time(struct rtc_time *rtc_tm)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       rtc_tm->tm_sec = MSTK_REG_SEC(regs);
-       rtc_tm->tm_min = MSTK_REG_MIN(regs);
-       rtc_tm->tm_hour = MSTK_REG_HOUR(regs);
-       rtc_tm->tm_mday = MSTK_REG_DOM(regs);
-       rtc_tm->tm_mon = MSTK_REG_MONTH(regs);
-       rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-       rtc_tm->tm_wday = MSTK_REG_DOW(regs);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       rtc_tm->tm_mon--;
-       rtc_tm->tm_wday--;
-       rtc_tm->tm_year -= 1900;
-}
-
-static int mostek_set_rtc_time(struct rtc_time *rtc_tm)
-{
-       unsigned char mon, day, hrs, min, sec, wday;
-       void __iomem *regs = mstk48t02_regs;
-       unsigned int yrs;
-       u8 tmp;
-
-       yrs = rtc_tm->tm_year + 1900;
-       mon = rtc_tm->tm_mon + 1;
-       day = rtc_tm->tm_mday;
-       wday = rtc_tm->tm_wday + 1;
-       hrs = rtc_tm->tm_hour;
-       min = rtc_tm->tm_min;
-       sec = rtc_tm->tm_sec;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       MSTK_SET_REG_SEC(regs, sec);
-       MSTK_SET_REG_MIN(regs, min);
-       MSTK_SET_REG_HOUR(regs, hrs);
-       MSTK_SET_REG_DOW(regs, wday);
-       MSTK_SET_REG_DOM(regs, day);
-       MSTK_SET_REG_MONTH(regs, mon);
-       MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-
-       return 0;
-}
-
-struct mini_rtc_ops {
-       void (*get_rtc_time)(struct rtc_time *);
-       int (*set_rtc_time)(struct rtc_time *);
-};
-
-static struct mini_rtc_ops starfire_rtc_ops = {
-       .get_rtc_time = starfire_get_rtc_time,
-       .set_rtc_time = starfire_set_rtc_time,
-};
-
-static struct mini_rtc_ops hypervisor_rtc_ops = {
-       .get_rtc_time = hypervisor_get_rtc_time,
-       .set_rtc_time = hypervisor_set_rtc_time,
-};
-
-#ifdef CONFIG_PCI
-static struct mini_rtc_ops bq4802_rtc_ops = {
-       .get_rtc_time = bq4802_get_rtc_time,
-       .set_rtc_time = bq4802_set_rtc_time,
-};
-
-static struct mini_rtc_ops cmos_rtc_ops = {
-       .get_rtc_time = cmos_get_rtc_time,
-       .set_rtc_time = cmos_set_rtc_time,
-};
-#endif /* CONFIG_PCI */
-
-static struct mini_rtc_ops mostek_rtc_ops = {
-       .get_rtc_time = mostek_get_rtc_time,
-       .set_rtc_time = mostek_set_rtc_time,
-};
-
-static struct mini_rtc_ops *mini_rtc_ops;
-
-static inline void mini_get_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       mini_rtc_ops->get_rtc_time(time);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-}
-
-static inline int mini_set_rtc_time(struct rtc_time *time)
-{
-       unsigned long flags;
-       int err;
-
-       spin_lock_irqsave(&rtc_lock, flags);
-       err = mini_rtc_ops->set_rtc_time(time);
-       spin_unlock_irqrestore(&rtc_lock, flags);
-
-       return err;
-}
-
-static int mini_rtc_ioctl(struct inode *inode, struct file *file,
-                         unsigned int cmd, unsigned long arg)
-{
-       struct rtc_time wtime;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-
-       case RTC_PLL_GET:
-               return -EINVAL;
-
-       case RTC_PLL_SET:
-               return -EINVAL;
-
-       case RTC_UIE_OFF:       /* disable ints from RTC updates.       */
-               return 0;
-
-       case RTC_UIE_ON:        /* enable ints for RTC updates. */
-               return -EINVAL;
-
-       case RTC_RD_TIME:       /* Read the time/date from RTC  */
-               /* this doesn't get week-day, who cares */
-               memset(&wtime, 0, sizeof(wtime));
-               mini_get_rtc_time(&wtime);
-
-               return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
-
-       case RTC_SET_TIME:      /* Set the RTC */
-           {
-               int year, days;
-
-               if (!capable(CAP_SYS_TIME))
-                       return -EACCES;
-
-               if (copy_from_user(&wtime, argp, sizeof(wtime)))
-                       return -EFAULT;
-
-               year = wtime.tm_year + 1900;
-               days = month_days[wtime.tm_mon] +
-                      ((wtime.tm_mon == 1) && leapyear(year));
-
-               if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
-                   (wtime.tm_mday < 1))
-                       return -EINVAL;
-
-               if (wtime.tm_mday < 0 || wtime.tm_mday > days)
-                       return -EINVAL;
-
-               if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
-                   wtime.tm_min < 0 || wtime.tm_min >= 60 ||
-                   wtime.tm_sec < 0 || wtime.tm_sec >= 60)
-                       return -EINVAL;
-
-               return mini_set_rtc_time(&wtime);
-           }
-       }
-
-       return -EINVAL;
-}
-
-static int mini_rtc_open(struct inode *inode, struct file *file)
-{
-       lock_kernel();
-       if (mini_rtc_status & RTC_IS_OPEN) {
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       mini_rtc_status |= RTC_IS_OPEN;
-       unlock_kernel();
-
-       return 0;
-}
-
-static int mini_rtc_release(struct inode *inode, struct file *file)
-{
-       mini_rtc_status &= ~RTC_IS_OPEN;
-       return 0;
-}
-
-
-static const struct file_operations mini_rtc_fops = {
-       .owner          = THIS_MODULE,
-       .ioctl          = mini_rtc_ioctl,
-       .open           = mini_rtc_open,
-       .release        = mini_rtc_release,
-};
-
-static struct miscdevice rtc_mini_dev =
-{
-       .minor          = RTC_MINOR,
-       .name           = "rtc",
-       .fops           = &mini_rtc_fops,
-};
-
-static int __init rtc_mini_init(void)
-{
-       int retval;
-
-       if (tlb_type == hypervisor)
-               mini_rtc_ops = &hypervisor_rtc_ops;
-       else if (this_is_starfire)
-               mini_rtc_ops = &starfire_rtc_ops;
-#ifdef CONFIG_PCI
-       else if (bq4802_regs)
-               mini_rtc_ops = &bq4802_rtc_ops;
-       else if (ds1287_regs)
-               mini_rtc_ops = &cmos_rtc_ops;
-#endif /* CONFIG_PCI */
-       else if (mstk48t02_regs)
-               mini_rtc_ops = &mostek_rtc_ops;
-       else
-               return -ENODEV;
-
-       printk(KERN_INFO "Mini RTC Driver\n");
-
-       retval = misc_register(&rtc_mini_dev);
-       if (retval < 0)
-               return retval;
-
-       return 0;
-}
-
-static void __exit rtc_mini_exit(void)
-{
-       misc_deregister(&rtc_mini_dev);
-}
-
 int __devinit read_current_timer(unsigned long *timer_val)
 {
        *timer_val = tick_ops->get_tick();
        return 0;
 }
-
-module_init(rtc_mini_init);
-module_exit(rtc_mini_exit);
index c824df13f589a31bdd048ddc1464f8d7e1c9e6d9..81ccd22e78d45d538225feae4b68a4d9257d1f77 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/timer.h>
 #include <asm/head.h>
 #include <asm/prom.h>
+#include <asm/memctrl.h>
 
 #include "entry.h"
 #include "kstack.h"
@@ -129,6 +130,56 @@ void do_BUG(const char *file, int line)
 }
 #endif
 
+static DEFINE_SPINLOCK(dimm_handler_lock);
+static dimm_printer_t dimm_handler;
+
+static int sprintf_dimm(int synd_code, unsigned long paddr, char *buf, int buflen)
+{
+       unsigned long flags;
+       int ret = -ENODEV;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (dimm_handler) {
+               ret = dimm_handler(synd_code, paddr, buf, buflen);
+       } else if (tlb_type == spitfire) {
+               if (prom_getunumber(synd_code, paddr, buf, buflen) == -1)
+                       ret = -EINVAL;
+               else
+                       ret = 0;
+       } else
+               ret = -ENODEV;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+       return ret;
+}
+
+int register_dimm_printer(dimm_printer_t func)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (!dimm_handler)
+               dimm_handler = func;
+       else
+               ret = -EEXIST;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(register_dimm_printer);
+
+void unregister_dimm_printer(dimm_printer_t func)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&dimm_handler_lock, flags);
+       if (dimm_handler == func)
+               dimm_handler = NULL;
+       spin_unlock_irqrestore(&dimm_handler_lock, flags);
+}
+EXPORT_SYMBOL_GPL(unregister_dimm_printer);
+
 void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
        siginfo_t info;
@@ -291,10 +342,7 @@ void sun4v_data_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
 }
 
 #ifdef CONFIG_PCI
-/* This is really pathetic... */
-extern volatile int pci_poke_in_progress;
-extern volatile int pci_poke_cpu;
-extern volatile int pci_poke_faulted;
+#include "pci_impl.h"
 #endif
 
 /* When access exceptions happen, we must do this. */
@@ -376,8 +424,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
 
        if (udbl & bit) {
                scode = ecc_syndrome_table[udbl & 0xff];
-               if (prom_getunumber(scode, afar,
-                                   memmod_str, sizeof(memmod_str)) == -1)
+               if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
                        p = syndrome_unknown;
                else
                        p = memmod_str;
@@ -388,8 +435,7 @@ static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, un
 
        if (udbh & bit) {
                scode = ecc_syndrome_table[udbh & 0xff];
-               if (prom_getunumber(scode, afar,
-                                   memmod_str, sizeof(memmod_str)) == -1)
+               if (sprintf_dimm(scode, afar, memmod_str, sizeof(memmod_str)) < 0)
                        p = syndrome_unknown;
                else
                        p = memmod_str;
@@ -1062,8 +1108,6 @@ static const char *cheetah_get_string(unsigned long bit)
        return "???";
 }
 
-extern int chmc_getunumber(int, unsigned long, char *, int);
-
 static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *info,
                               unsigned long afsr, unsigned long afar, int recoverable)
 {
@@ -1105,7 +1149,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
 
                syndrome = (afsr & CHAFSR_E_SYNDROME) >> CHAFSR_E_SYNDROME_SHIFT;
                syndrome = cheetah_ecc_syntab[syndrome];
-               ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+               ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
                if (ret != -1)
                        printk("%s" "ERROR(%d): AFAR E-syndrome [%s]\n",
                               (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -1116,7 +1160,7 @@ static void cheetah_log_errors(struct pt_regs *regs, struct cheetah_err_info *in
 
                syndrome = (afsr & CHAFSR_M_SYNDROME) >> CHAFSR_M_SYNDROME_SHIFT;
                syndrome = cheetah_mtag_syntab[syndrome];
-               ret = chmc_getunumber(syndrome, afar, unum, sizeof(unum));
+               ret = sprintf_dimm(syndrome, afar, unum, sizeof(unum));
                if (ret != -1)
                        printk("%s" "ERROR(%d): AFAR M-syndrome [%s]\n",
                               (recoverable ? KERN_WARNING : KERN_CRIT),
@@ -2224,7 +2268,6 @@ void die_if_kernel(char *str, struct pt_regs *regs)
 
 extern int handle_popc(u32 insn, struct pt_regs *regs);
 extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
-extern int vis_emul(struct pt_regs *, unsigned int);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
index a490077891a4c532e399e062830d3e932269af65..92b1f8ec01de3837572175f5062c28394327ea67 100644 (file)
@@ -152,7 +152,7 @@ show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
 static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
                   show_pciobppath_attr, NULL);
 
-struct device_node *cdev_node;
+static struct device_node *cdev_node;
 
 static struct vio_dev *root_vdev;
 static u64 cdev_cfg_handle;
@@ -371,9 +371,9 @@ static struct mdesc_notifier_client vio_ds_notifier = {
        .node_name      = "domain-services-port",
 };
 
-const char *channel_devices_node = "channel-devices";
-const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
-const char *cfg_handle_prop = "cfg-handle";
+static const char *channel_devices_node = "channel-devices";
+static const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
+static const char *cfg_handle_prop = "cfg-handle";
 
 static int __init vio_init(void)
 {
index c3fd64706b53f031e7663814a8d41923212b869f..9e05cb5cb855ba5d0f2d3367d6e0a4e5023fe663 100644 (file)
@@ -243,7 +243,7 @@ static inline unsigned int *fps_regaddr(struct fpustate *f,
 struct edge_tab {
        u16 left, right;
 };
-struct edge_tab edge8_tab[8] = {
+static struct edge_tab edge8_tab[8] = {
        { 0xff, 0x80 },
        { 0x7f, 0xc0 },
        { 0x3f, 0xe0 },
@@ -253,7 +253,7 @@ struct edge_tab edge8_tab[8] = {
        { 0x03, 0xfe },
        { 0x01, 0xff },
 };
-struct edge_tab edge8_tab_l[8] = {
+static struct edge_tab edge8_tab_l[8] = {
        { 0xff, 0x01 },
        { 0xfe, 0x03 },
        { 0xfc, 0x07 },
@@ -263,23 +263,23 @@ struct edge_tab edge8_tab_l[8] = {
        { 0xc0, 0x7f },
        { 0x80, 0xff },
 };
-struct edge_tab edge16_tab[4] = {
+static struct edge_tab edge16_tab[4] = {
        { 0xf, 0x8 },
        { 0x7, 0xc },
        { 0x3, 0xe },
        { 0x1, 0xf },
 };
-struct edge_tab edge16_tab_l[4] = {
+static struct edge_tab edge16_tab_l[4] = {
        { 0xf, 0x1 },
        { 0xe, 0x3 },
        { 0xc, 0x7 },
        { 0x8, 0xf },
 };
-struct edge_tab edge32_tab[2] = {
+static struct edge_tab edge32_tab[2] = {
        { 0x3, 0x2 },
        { 0x1, 0x3 },
 };
-struct edge_tab edge32_tab_l[2] = {
+static struct edge_tab edge32_tab_l[2] = {
        { 0x3, 0x1 },
        { 0x2, 0x3 },
 };
index ea7d7ae76bc24d20f3e731507b478f032986f150..a9e474bf63856077826d7ba0974ee887ca8d8c46 100644 (file)
@@ -51,43 +51,6 @@ static inline int notify_page_fault(struct pt_regs *regs)
 }
 #endif
 
-/*
- * To debug kernel to catch accesses to certain virtual/physical addresses.
- * Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
- * flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
- * Caller passes in a 64bit aligned addr, with mask set to the bytes that need to be
- * watched. This is only useful on a single cpu machine for now. After the watchpoint
- * is detected, the process causing it will be killed, thus preventing an infinite loop.
- */
-void set_brkpt(unsigned long addr, unsigned char mask, int flags, int mode)
-{
-       unsigned long lsubits;
-
-       __asm__ __volatile__("ldxa [%%g0] %1, %0"
-                            : "=r" (lsubits)
-                            : "i" (ASI_LSU_CONTROL));
-       lsubits &= ~(LSU_CONTROL_PM | LSU_CONTROL_VM |
-                    LSU_CONTROL_PR | LSU_CONTROL_VR |
-                    LSU_CONTROL_PW | LSU_CONTROL_VW);
-
-       __asm__ __volatile__("stxa      %0, [%1] %2\n\t"
-                            "membar    #Sync"
-                            : /* no outputs */
-                            : "r" (addr), "r" (mode ? VIRT_WATCHPOINT : PHYS_WATCHPOINT),
-                              "i" (ASI_DMMU));
-
-       lsubits |= ((unsigned long)mask << (mode ? 25 : 33));
-       if (flags & VM_READ)
-               lsubits |= (mode ? LSU_CONTROL_VR : LSU_CONTROL_PR);
-       if (flags & VM_WRITE)
-               lsubits |= (mode ? LSU_CONTROL_VW : LSU_CONTROL_PW);
-       __asm__ __volatile__("stxa %0, [%%g0] %1\n\t"
-                            "membar #Sync"
-                            : /* no outputs */
-                            : "r" (lsubits), "i" (ASI_LSU_CONTROL)
-                            : "memory");
-}
-
 static void __kprobes unhandled_fault(unsigned long address,
                                      struct task_struct *tsk,
                                      struct pt_regs *regs)
index a41df7bef0356eef702e247f7ef2bb05a8679acb..3c10daf8fc015799a300ffc86d3d014b8f7ae5ee 100644 (file)
 #include <asm/tsb.h>
 #include <asm/hypervisor.h>
 #include <asm/prom.h>
-#include <asm/sstate.h>
 #include <asm/mdesc.h>
 #include <asm/cpudata.h>
 #include <asm/irq.h>
 
-#define MAX_PHYS_ADDRESS       (1UL << 42UL)
-#define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
-#define KPTE_BITMAP_BYTES      \
-       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+#include "init.h"
 
 unsigned long kern_linear_pte_xor[2] __read_mostly;
 
@@ -416,17 +412,9 @@ void mmu_info(struct seq_file *m)
 #endif /* CONFIG_DEBUG_DCFLUSH */
 }
 
-struct linux_prom_translation {
-       unsigned long virt;
-       unsigned long size;
-       unsigned long data;
-};
-
-/* Exported for kernel TLB miss handling in ktlb.S */
 struct linux_prom_translation prom_trans[512] __read_mostly;
 unsigned int prom_trans_ents __read_mostly;
 
-/* Exported for SMP bootup purposes. */
 unsigned long kern_locked_tte_data;
 
 /* The obp translations are saved based on 8k pagesize, since obp can
@@ -938,6 +926,10 @@ int of_node_to_nid(struct device_node *dp)
        int count, nid;
        u64 grp;
 
+       /* This is the right thing to do on currently supported
+        * SUN4U NUMA platforms as well, as the PCI controller does
+        * not sit behind any particular memory controller.
+        */
        if (!mlgroups)
                return -1;
 
@@ -1206,8 +1198,44 @@ out:
        return err;
 }
 
+static int __init numa_parse_jbus(void)
+{
+       unsigned long cpu, index;
+
+       /* NUMA node id is encoded in bits 36 and higher, and there is
+        * a 1-to-1 mapping from CPU ID to NUMA node ID.
+        */
+       index = 0;
+       for_each_present_cpu(cpu) {
+               numa_cpu_lookup_table[cpu] = index;
+               numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu);
+               node_masks[index].mask = ~((1UL << 36UL) - 1UL);
+               node_masks[index].val = cpu << 36UL;
+
+               index++;
+       }
+       num_node_masks = index;
+
+       add_node_ranges();
+
+       for (index = 0; index < num_node_masks; index++) {
+               allocate_node_data(index);
+               node_set_online(index);
+       }
+
+       return 0;
+}
+
 static int __init numa_parse_sun4u(void)
 {
+       if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+               unsigned long ver;
+
+               __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+               if ((ver >> 32UL) == __JALAPENO_ID ||
+                   (ver >> 32UL) == __SERRANO_ID)
+                       return numa_parse_jbus();
+       }
        return -1;
 }
 
@@ -1633,8 +1661,6 @@ void __cpuinit sun4v_ktsb_register(void)
 
 /* paging_init() sets up the page tables */
 
-extern void central_probe(void);
-
 static unsigned long last_valid_pfn;
 pgd_t swapper_pg_dir[2048];
 
@@ -1679,8 +1705,6 @@ void __init paging_init(void)
        kern_base = (prom_boot_mapping_phys_low >> 22UL) << 22UL;
        kern_size = (unsigned long)&_end - (unsigned long)KERNBASE;
 
-       sstate_booting();
-
        /* Invalidate both kernel TSBs.  */
        memset(swapper_tsb, 0x40, sizeof(swapper_tsb));
 #ifndef CONFIG_DEBUG_PAGEALLOC
@@ -1803,9 +1827,6 @@ void __init paging_init(void)
        }
 
        printk("Booting Linux...\n");
-
-       central_probe();
-       cpu_probe();
 }
 
 int __init page_in_phys_avail(unsigned long paddr)
@@ -2032,7 +2053,6 @@ pgprot_t PAGE_COPY __read_mostly;
 pgprot_t PAGE_SHARED __read_mostly;
 EXPORT_SYMBOL(PAGE_SHARED);
 
-pgprot_t PAGE_EXEC __read_mostly;
 unsigned long pg_iobits __read_mostly;
 
 unsigned long _PAGE_IE __read_mostly;
@@ -2045,14 +2065,6 @@ unsigned long _PAGE_CACHE __read_mostly;
 EXPORT_SYMBOL(_PAGE_CACHE);
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-
-#define VMEMMAP_CHUNK_SHIFT    22
-#define VMEMMAP_CHUNK          (1UL << VMEMMAP_CHUNK_SHIFT)
-#define VMEMMAP_CHUNK_MASK     ~(VMEMMAP_CHUNK - 1UL)
-#define VMEMMAP_ALIGN(x)       (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
-
-#define VMEMMAP_SIZE   ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
-                         sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
 unsigned long vmemmap_table[VMEMMAP_SIZE];
 
 int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
@@ -2136,7 +2148,6 @@ static void __init sun4u_pgprot_init(void)
                                       _PAGE_CACHE_4U | _PAGE_P_4U |
                                       __ACCESS_BITS_4U | __DIRTY_BITS_4U |
                                       _PAGE_EXEC_4U | _PAGE_L_4U);
-       PAGE_EXEC = __pgprot(_PAGE_EXEC_4U);
 
        _PAGE_IE = _PAGE_IE_4U;
        _PAGE_E = _PAGE_E_4U;
@@ -2147,10 +2158,10 @@ static void __init sun4u_pgprot_init(void)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4U) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4U) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[0] |= (_PAGE_CP_4U | _PAGE_CV_4U |
                                   _PAGE_P_4U | _PAGE_W_4U);
@@ -2188,7 +2199,6 @@ static void __init sun4v_pgprot_init(void)
                                __ACCESS_BITS_4V | __DIRTY_BITS_4V |
                                _PAGE_EXEC_4V);
        PAGE_KERNEL_LOCKED = PAGE_KERNEL;
-       PAGE_EXEC = __pgprot(_PAGE_EXEC_4V);
 
        _PAGE_IE = _PAGE_IE_4V;
        _PAGE_E = _PAGE_E_4V;
@@ -2196,20 +2206,20 @@ static void __init sun4v_pgprot_init(void)
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[0] = (_PAGE_VALID | _PAGE_SZ4MB_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[0] |= (_PAGE_CP_4V | _PAGE_CV_4V |
                                   _PAGE_P_4V | _PAGE_W_4V);
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZBITS_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #else
        kern_linear_pte_xor[1] = (_PAGE_VALID | _PAGE_SZ256MB_4V) ^
-               0xfffff80000000000;
+               0xfffff80000000000UL;
 #endif
        kern_linear_pte_xor[1] |= (_PAGE_CP_4V | _PAGE_CV_4V |
                                   _PAGE_P_4V | _PAGE_W_4V);
diff --git a/arch/sparc64/mm/init.h b/arch/sparc64/mm/init.h
new file mode 100644 (file)
index 0000000..1606387
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _SPARC64_MM_INIT_H
+#define _SPARC64_MM_INIT_H
+
+/* Most of the symbols in this file are defined in init.c and
+ * marked non-static so that assembler code can get at them.
+ */
+
+#define MAX_PHYS_ADDRESS       (1UL << 42UL)
+#define KPTE_BITMAP_CHUNK_SZ   (256UL * 1024UL * 1024UL)
+#define KPTE_BITMAP_BYTES      \
+       ((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 8)
+
+extern unsigned long kern_linear_pte_xor[2];
+extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+extern unsigned int sparc64_highest_unlocked_tlb_ent;
+extern unsigned long sparc64_kern_pri_context;
+extern unsigned long sparc64_kern_pri_nuc_bits;
+extern unsigned long sparc64_kern_sec_context;
+extern void mmu_info(struct seq_file *m);
+
+struct linux_prom_translation {
+       unsigned long virt;
+       unsigned long size;
+       unsigned long data;
+};
+
+/* Exported for kernel TLB miss handling in ktlb.S */
+extern struct linux_prom_translation prom_trans[512];
+extern unsigned int prom_trans_ents;
+
+/* Exported for SMP bootup purposes. */
+extern unsigned long kern_locked_tte_data;
+
+extern void prom_world(int enter);
+
+extern void free_initmem(void);
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+#define VMEMMAP_CHUNK_SHIFT    22
+#define VMEMMAP_CHUNK          (1UL << VMEMMAP_CHUNK_SHIFT)
+#define VMEMMAP_CHUNK_MASK     ~(VMEMMAP_CHUNK - 1UL)
+#define VMEMMAP_ALIGN(x)       (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
+
+#define VMEMMAP_SIZE   ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
+                         sizeof(struct page *)) >> VMEMMAP_CHUNK_SHIFT)
+extern unsigned long vmemmap_table[VMEMMAP_SIZE];
+#endif
+
+#endif /* _SPARC64_MM_INIT_H */
index ae24919cba7cf8bef8a0ad4f8455f5c871e3920f..d8f21e24a82f8c98f0a708bd1a493058a51b49bb 100644 (file)
@@ -19,7 +19,7 @@
 
 /* Heavily inspired by the ppc64 code.  */
 
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers) = { 0, };
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
 void flush_tlb_pending(void)
 {
index 44d4f2130d014be68f3a0171d2e4e980b78443ad..fc8351f374fd466b8f9b287a6f5d4a2ec3b0fd32 100644 (file)
@@ -778,23 +778,45 @@ config X86_REBOOTFIXUPS
          Say N otherwise.
 
 config MICROCODE
-       tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+       tristate "/dev/cpu/microcode - microcode support"
        select FW_LOADER
        ---help---
          If you say Y here, you will be able to update the microcode on
-         Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
-         Pentium III, Pentium 4, Xeon etc.  You will obviously need the
-         actual microcode binary data itself which is not shipped with the
-         Linux kernel.
+         certain Intel and AMD processors. The Intel support is for the
+         IA32 family, e.g. Pentium Pro, Pentium II, Pentium III,
+         Pentium 4, Xeon etc. The AMD support is for family 0x10 and
+         0x11 processors, e.g. Opteron, Phenom and Turion 64 Ultra.
+         You will obviously need the actual microcode binary data itself
+         which is not shipped with the Linux kernel.
 
-         For latest news and information on obtaining all the required
-         ingredients for this driver, check:
-         <http://www.urbanmyth.org/microcode/>.
+         This option selects the general module only, you need to select
+         at least one vendor specific module as well.
 
          To compile this driver as a module, choose M here: the
          module will be called microcode.
 
-config MICROCODE_OLD_INTERFACE
+config MICROCODE_INTEL
+       bool "Intel microcode patch loading support"
+       depends on MICROCODE
+       default MICROCODE
+       select FW_LOADER
+       --help---
+         This options enables microcode patch loading support for Intel
+         processors.
+
+         For latest news and information on obtaining all the required
+         Intel ingredients for this driver, check:
+         <http://www.urbanmyth.org/microcode/>.
+
+config MICROCODE_AMD
+       bool "AMD microcode patch loading support"
+       depends on MICROCODE
+       select FW_LOADER
+       --help---
+         If you select this option, microcode patch loading support for AMD
+        processors will be enabled.
+
+   config MICROCODE_OLD_INTERFACE
        def_bool y
        depends on MICROCODE
 
@@ -1061,6 +1083,56 @@ config HIGHPTE
          low memory.  Setting this option will put user-space page table
          entries in high memory.
 
+config X86_CHECK_BIOS_CORRUPTION
+        bool "Check for low memory corruption"
+       help
+        Periodically check for memory corruption in low memory, which
+        is suspected to be caused by BIOS.  Even when enabled in the
+        configuration, it is disabled at runtime.  Enable it by
+        setting "memory_corruption_check=1" on the kernel command
+        line.  By default it scans the low 64k of memory every 60
+        seconds; see the memory_corruption_check_size and
+        memory_corruption_check_period parameters in
+        Documentation/kernel-parameters.txt to adjust this.
+
+        When enabled with the default parameters, this option has
+        almost no overhead, as it reserves a relatively small amount
+        of memory and scans it infrequently.  It both detects corruption
+        and prevents it from affecting the running system.
+
+        It is, however, intended as a diagnostic tool; if repeatable
+        BIOS-originated corruption always affects the same memory,
+        you can use memmap= to prevent the kernel from using that
+        memory.
+
+config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+        bool "Set the default setting of memory_corruption_check"
+       depends on X86_CHECK_BIOS_CORRUPTION
+       default y
+       help
+        Set whether the default state of memory_corruption_check is
+        on or off.
+
+config X86_RESERVE_LOW_64K
+        bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
+       default y
+       help
+        Reserve the first 64K of physical RAM on BIOSes that are known
+        to potentially corrupt that memory range. A numbers of BIOSes are
+        known to utilize this area during suspend/resume, so it must not
+        be used by the kernel.
+
+        Set this to N if you are absolutely sure that you trust the BIOS
+        to get all its memory reservations and usages right.
+
+        If you have doubts about the BIOS (e.g. suspend/resume does not
+        work or there's kernel crashes after certain hardware hotplug
+        events) and it's not AMI or Phoenix, then you might want to enable
+        X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
+        corruption patterns.
+
+        Say Y if unsure.
+
 config MATH_EMULATION
        bool
        prompt "Math emulation" if X86_32
index f8843c3ae77d5b2e7244e4189666097625d1c825..c5f1013605203de94c93af52d105512ace47c1c6 100644 (file)
@@ -420,7 +420,6 @@ config X86_DEBUGCTLMSR
        depends on !(MK6 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MCYRIXIII || M586MMX || M586TSC || M586 || M486 || M386)
 
 menuconfig PROCESSOR_SELECT
-       default y
        bool "Supported processor vendors" if EMBEDDED
        help
          This lets you choose what x86 vendor support code your kernel
@@ -430,48 +429,97 @@ config CPU_SUP_INTEL
        default y
        bool "Support Intel processors" if PROCESSOR_SELECT
        help
-         This enables extended support for Intel processors
+         This enables detection, tunings and quirks for Intel processors
+
+         You need this enabled if you want your kernel to run on an
+         Intel CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on an Intel
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_CYRIX_32
        default y
        bool "Support Cyrix processors" if PROCESSOR_SELECT
        depends on !64BIT
        help
-         This enables extended support for Cyrix processors
+         This enables detection, tunings and quirks for Cyrix processors
+
+         You need this enabled if you want your kernel to run on a
+         Cyrix CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Cyrix
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_AMD
        default y
        bool "Support AMD processors" if PROCESSOR_SELECT
        help
-         This enables extended support for AMD processors
+         This enables detection, tunings and quirks for AMD processors
+
+         You need this enabled if you want your kernel to run on an
+         AMD CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on an AMD
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_CENTAUR_32
        default y
        bool "Support Centaur processors" if PROCESSOR_SELECT
        depends on !64BIT
        help
-         This enables extended support for Centaur processors
+         This enables detection, tunings and quirks for Centaur processors
+
+         You need this enabled if you want your kernel to run on a
+         Centaur CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Centaur
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_CENTAUR_64
        default y
        bool "Support Centaur processors" if PROCESSOR_SELECT
        depends on 64BIT
        help
-         This enables extended support for Centaur processors
+         This enables detection, tunings and quirks for Centaur processors
+
+         You need this enabled if you want your kernel to run on a
+         Centaur CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Centaur
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_TRANSMETA_32
        default y
        bool "Support Transmeta processors" if PROCESSOR_SELECT
        depends on !64BIT
        help
-         This enables extended support for Transmeta processors
+         This enables detection, tunings and quirks for Transmeta processors
+
+         You need this enabled if you want your kernel to run on a
+         Transmeta CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a Transmeta
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config CPU_SUP_UMC_32
        default y
        bool "Support UMC processors" if PROCESSOR_SELECT
        depends on !64BIT
        help
-         This enables extended support for UMC processors
+         This enables detection, tunings and quirks for UMC processors
+
+         You need this enabled if you want your kernel to run on a
+         UMC CPU. Disabling this option on other types of CPUs
+         makes the kernel a tiny bit smaller. Disabling it on a UMC
+         CPU might render the kernel unbootable.
+
+         If unsure, say N.
 
 config X86_DS
        bool "Debug Store support"
index 092f019e033a7a42d65b9d9297c02435c45347d0..2a3dfbd5e677b548e5e75f43da69e934b90a7eff 100644 (file)
@@ -43,6 +43,19 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
+config EARLY_PRINTK_DBGP
+       bool "Early printk via EHCI debug port"
+       default n
+       depends on EARLY_PRINTK && PCI
+       help
+         Write kernel log output directly into the EHCI debug port.
+
+         This is useful for kernel debugging when your machine crashes very
+         early before the console code is initialized. For normal operation
+         it is not recommended because it looks ugly and doesn't cooperate
+         with klogd/syslogd or the X server. You should normally N here,
+         unless you want to debug such a crash. You need usb debug device.
+
 config DEBUG_STACKOVERFLOW
        bool "Check for stack overflows"
        depends on DEBUG_KERNEL
index e372b584e9190ab5095e3b0defdde166625361e9..b72b4f7531138cbc4c5042ac90942e752a74b8a4 100644 (file)
@@ -45,3 +45,8 @@ cflags-$(CONFIG_MGEODEGX1)    += -march=pentium-mmx
 # cpu entries
 cflags-$(CONFIG_X86_GENERIC)   += $(call tune,generic,$(call tune,i686))
 
+# Bug fix for binutils: this option is required in order to keep
+# binutils from generating NOPL instructions against our will.
+ifneq ($(CONFIG_X86_P6_NOP),y)
+cflags-y                       += $(call cc-option,-Wa$(comma)-mtune=generic32,)
+endif
index 7ee102f9c4f8c86b098c71168478e1a79443c97a..cd48c7210016f0f2be76daa999b2a5d542019bce 100644 (file)
@@ -72,9 +72,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
 KBUILD_CFLAGS +=   $(call cc-option,-m32)
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 
-$(obj)/zImage:  IMAGE_OFFSET := 0x1000
 $(obj)/zImage:  asflags-y := $(SVGA_MODE) $(RAMDISK)
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
 $(obj)/bzImage: ccflags-y := -D__BIG_KERNEL__
 $(obj)/bzImage: asflags-y := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
 $(obj)/bzImage: BUILDFLAGS   := -b
@@ -117,7 +115,7 @@ $(obj)/setup.bin: $(obj)/setup.elf FORCE
        $(call if_changed,objcopy)
 
 $(obj)/compressed/vmlinux: FORCE
-       $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
+       $(Q)$(MAKE) $(build)=$(obj)/compressed $@
 
 # Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
 FDARGS =
@@ -181,6 +179,7 @@ isoimage: $(BOOTIMAGE)
        mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
                -no-emul-boot -boot-load-size 4 -boot-info-table \
                $(obj)/isoimage
+       isohybrid $(obj)/image.iso 2>/dev/null || true
        rm -rf $(obj)/isoimage
 
 zlilo: $(BOOTIMAGE)
index 92fdd35bd93e4fca0ac3b7a2d6ed7736f8094897..1771c804e02f57b26d5d4f9f1db8cdb1f7a4ed62 100644 (file)
@@ -27,9 +27,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
 
-ifeq ($(CONFIG_X86_32),y)
-targets += vmlinux.bin.all vmlinux.relocs
-hostprogs-y := relocs
+targets += vmlinux.bin.all vmlinux.relocs relocs
+hostprogs-$(CONFIG_X86_32) += relocs
 
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $<
@@ -43,6 +42,8 @@ quiet_cmd_relocbin = BUILD   $@
 $(obj)/vmlinux.bin.all: $(vmlinux.bin.all-y) FORCE
        $(call if_changed,relocbin)
 
+ifeq ($(CONFIG_X86_32),y)
+
 ifdef CONFIG_RELOCATABLE
 $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin.all FORCE
        $(call if_changed,gzip)
@@ -59,6 +60,5 @@ $(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
 LDFLAGS_piggy.o := -r --format binary --oformat elf64-x86-64 -T
 endif
 
-
 $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
        $(call if_changed,ld)
index d93cbc6464d0f8aa8aed3479b1b88a66993afa67..1aae8f3e5ca1912b6eb60ad75e3c120af1110bed 100644 (file)
@@ -41,6 +41,7 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
        char *mbrbuf_ptr, *mbrbuf_end;
        u32 buf_base, mbr_base;
        extern char _end[];
+       u16 mbr_magic;
 
        sector_size = ei->params.bytes_per_sector;
        if (!sector_size)
@@ -58,11 +59,15 @@ static u32 read_mbr_sig(u8 devno, struct edd_info *ei, u32 *mbrsig)
        if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
                return -1;
 
+       memset(mbrbuf_ptr, 0, sector_size);
        if (read_mbr(devno, mbrbuf_ptr))
                return -1;
 
        *mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
-       return 0;
+       mbr_magic = *(u16 *)&mbrbuf_ptr[510];
+
+       /* check for valid MBR magic */
+       return mbr_magic == 0xAA55 ? 0 : -1;
 }
 
 static int get_edd_info(u8 devno, struct edd_info *ei)
index 401ad998ad08d7cd63943a5b7a7ae893264b5e3f..1e6fe0214c85a34788f8ddb55f3d9b3f559b0f41 100644 (file)
@@ -224,7 +224,7 @@ static void vesa_store_pm_info(void)
 static void vesa_store_mode_params_graphics(void)
 {
        /* Tell the kernel we're in VESA graphics mode */
-       boot_params.screen_info.orig_video_isVGA = 0x23;
+       boot_params.screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
 
        /* Mode parameters */
        boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
index ef9a52005ec9f726dbf018d43021fd1b3bf3edf8..ca226ca31288254bd40eb45ba55047c04b01bb09 100644 (file)
@@ -1535,7 +1535,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
index e620ea6e2a7a7d7093cdfb829a39487fe2645ee7..2c4b1c771e28dd3758388a8a634414577db9fd91 100644 (file)
@@ -1505,7 +1505,6 @@ CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_VGA_CONSOLE=y
 CONFIG_VGACON_SOFT_SCROLLBACK=y
 CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=64
-CONFIG_VIDEO_SELECT=y
 CONFIG_DUMMY_CONSOLE=y
 # CONFIG_FRAMEBUFFER_CONSOLE is not set
 CONFIG_LOGO=y
index 8d64c1bc84743bf8e04a8435eb8cf9becd927369..4bc02b23674b5dfaaf91e813fb2be320dc57cd23 100644 (file)
@@ -351,31 +351,28 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
        savesegment(es, tmp);
        err |= __put_user(tmp, (unsigned int __user *)&sc->es);
 
-       err |= __put_user((u32)regs->di, &sc->di);
-       err |= __put_user((u32)regs->si, &sc->si);
-       err |= __put_user((u32)regs->bp, &sc->bp);
-       err |= __put_user((u32)regs->sp, &sc->sp);
-       err |= __put_user((u32)regs->bx, &sc->bx);
-       err |= __put_user((u32)regs->dx, &sc->dx);
-       err |= __put_user((u32)regs->cx, &sc->cx);
-       err |= __put_user((u32)regs->ax, &sc->ax);
-       err |= __put_user((u32)regs->cs, &sc->cs);
-       err |= __put_user((u32)regs->ss, &sc->ss);
+       err |= __put_user(regs->di, &sc->di);
+       err |= __put_user(regs->si, &sc->si);
+       err |= __put_user(regs->bp, &sc->bp);
+       err |= __put_user(regs->sp, &sc->sp);
+       err |= __put_user(regs->bx, &sc->bx);
+       err |= __put_user(regs->dx, &sc->dx);
+       err |= __put_user(regs->cx, &sc->cx);
+       err |= __put_user(regs->ax, &sc->ax);
+       err |= __put_user(regs->cs, &sc->cs);
+       err |= __put_user(regs->ss, &sc->ss);
        err |= __put_user(current->thread.trap_no, &sc->trapno);
        err |= __put_user(current->thread.error_code, &sc->err);
-       err |= __put_user((u32)regs->ip, &sc->ip);
-       err |= __put_user((u32)regs->flags, &sc->flags);
-       err |= __put_user((u32)regs->sp, &sc->sp_at_signal);
+       err |= __put_user(regs->ip, &sc->ip);
+       err |= __put_user(regs->flags, &sc->flags);
+       err |= __put_user(regs->sp, &sc->sp_at_signal);
 
        tmp = save_i387_xstate_ia32(fpstate);
        if (tmp < 0)
                err = -EFAULT;
-       else {
-               clear_used_math();
-               stts();
+       else
                err |= __put_user(ptr_to_compat(tmp ? fpstate : NULL),
                                        &sc->fpstate);
-       }
 
        /* non-iBCS2 extensions.. */
        err |= __put_user(mask, &sc->oldmask);
@@ -444,21 +441,18 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
        frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       err |= __put_user(sig, &frame->sig);
-       if (err)
-               goto give_sigsegv;
+       if (__put_user(sig, &frame->sig))
+               return -EFAULT;
 
-       err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
-       if (err)
-               goto give_sigsegv;
+       if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+               return -EFAULT;
 
        if (_COMPAT_NSIG_WORDS > 1) {
-               err |= __copy_to_user(frame->extramask, &set->sig[1],
-                                     sizeof(frame->extramask));
-               if (err)
-                       goto give_sigsegv;
+               if (__copy_to_user(frame->extramask, &set->sig[1],
+                                  sizeof(frame->extramask)))
+                       return -EFAULT;
        }
 
        if (ka->sa.sa_flags & SA_RESTORER) {
@@ -479,7 +473,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
         */
        err |= __copy_to_user(frame->retcode, &code, 8);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long) frame;
@@ -502,10 +496,6 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
 #endif
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -533,14 +523,14 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
        err |= __put_user(sig, &frame->sig);
        err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
        err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
        err |= copy_siginfo_to_user32(&frame->info, info);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Create the ucontext.  */
        if (cpu_has_xsave)
@@ -556,7 +546,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                                     regs, set->sig[0]);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        if (ka->sa.sa_flags & SA_RESTORER)
                restorer = ka->sa.sa_restorer;
@@ -571,7 +561,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
         */
        err |= __copy_to_user(frame->retcode, &code, 8);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long) frame;
@@ -599,8 +589,4 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 #endif
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
index c9be69fedb7050f9baac78cac4bb415e05c45d7f..5098585f87ce8fdc29fd82fde6e53711238f11cd 100644 (file)
@@ -10,7 +10,7 @@ ifdef CONFIG_FTRACE
 # Do not profile debug and lowlevel utilities
 CFLAGS_REMOVE_tsc.o = -pg
 CFLAGS_REMOVE_rtc.o = -pg
-CFLAGS_REMOVE_paravirt.o = -pg
+CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
 endif
 
 #
@@ -51,7 +51,6 @@ obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
 obj-$(CONFIG_MCA)              += mca_32.o
 obj-$(CONFIG_X86_MSR)          += msr.o
 obj-$(CONFIG_X86_CPUID)                += cpuid.o
-obj-$(CONFIG_MICROCODE)                += microcode.o
 obj-$(CONFIG_PCI)              += early-quirks.o
 apm-y                          := apm_32.o
 obj-$(CONFIG_APM)              += apm.o
@@ -90,7 +89,7 @@ obj-$(CONFIG_DEBUG_NX_TEST)   += test_nx.o
 obj-$(CONFIG_VMI)              += vmi_32.o vmiclock_32.o
 obj-$(CONFIG_KVM_GUEST)                += kvm.o
 obj-$(CONFIG_KVM_CLOCK)                += kvmclock.o
-obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirt_patch_$(BITS).o
+obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirt_patch_$(BITS).o paravirt-spinlocks.o
 obj-$(CONFIG_PARAVIRT_CLOCK)   += pvclock.o
 
 obj-$(CONFIG_PCSPKR_PLATFORM)  += pcspeaker.o
@@ -100,6 +99,11 @@ scx200-y                    += scx200_32.o
 
 obj-$(CONFIG_OLPC)             += olpc.o
 
+microcode-y                            := microcode_core.o
+microcode-$(CONFIG_MICROCODE_INTEL)    += microcode_intel.o
+microcode-$(CONFIG_MICROCODE_AMD)      += microcode_amd.o
+obj-$(CONFIG_MICROCODE)                        += microcode.o
+
 ###
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
index c2ac1b4515a0b95f9dd54717127144b50cc550ee..eb875cdc7367c3aee3fcb285606c1e993cc808af 100644 (file)
@@ -1418,8 +1418,16 @@ static int __init force_acpi_ht(const struct dmi_system_id *d)
  */
 static int __init dmi_ignore_irq0_timer_override(const struct dmi_system_id *d)
 {
-       pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n", d->ident);
-       acpi_skip_timer_override = 1;
+       /*
+        * The ati_ixp4x0_rev() early PCI quirk should have set
+        * the acpi_skip_timer_override flag already:
+        */
+       if (!acpi_skip_timer_override) {
+               WARN(1, KERN_ERR "ati_ixp4x0 quirk not complete.\n");
+               pr_notice("%s detected: Ignoring BIOS IRQ0 pin2 override\n",
+                       d->ident);
+               acpi_skip_timer_override = 1;
+       }
        return 0;
 }
 
index 148fcfe22f17108f16cab1e865f123dab0f9507f..4cd8083c58be75d2eea19124ddf3758b15e860aa 100644 (file)
@@ -723,9 +723,7 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h)
        init_iommu_from_acpi(iommu, h);
        init_iommu_devices(iommu);
 
-       pci_enable_device(iommu->dev);
-
-       return 0;
+       return pci_enable_device(iommu->dev);
 }
 
 /*
index 7581b62df184b8b2166e6df667e5d9aa4493723e..fb789dd9e691cafffb4d25fc0e26b5c35b4c0869 100644 (file)
@@ -1121,16 +1121,5 @@ void __cpuinit cpu_init(void)
        xsave_init();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-void __cpuinit cpu_uninit(void)
-{
-       int cpu = raw_smp_processor_id();
-       cpu_clear(cpu, cpu_initialized);
-
-       /* lazy TLB state */
-       per_cpu(cpu_tlbstate, cpu).state = 0;
-       per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
-}
-#endif
 
 #endif
index a47798b59f07e82205cc6f24d2e4ccc5f0cb6db7..395acb12b0d1bfe1a5e1764d00ef4271b00a7e2f 100644 (file)
@@ -66,6 +66,6 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
                .ds             = __USER_DS,
                .fs             = __KERNEL_PERCPU,
 
-               .__cr3          = __pa(swapper_pg_dir)
+               .__cr3          = __phys_addr_const((unsigned long)swapper_pg_dir)
        }
 };
index 24bb5faf5efaefedcb578d4f4f27415a015833c7..733c4f8d42ea587437191881974c786bc6e9186e 100644 (file)
@@ -95,6 +95,52 @@ static void __init nvidia_bugs(int num, int slot, int func)
 
 }
 
+static u32 ati_ixp4x0_rev(int num, int slot, int func)
+{
+       u32 d;
+       u8  b;
+
+       b = read_pci_config_byte(num, slot, func, 0xac);
+       b &= ~(1<<5);
+       write_pci_config_byte(num, slot, func, 0xac, b);
+
+       d = read_pci_config(num, slot, func, 0x70);
+       d |= 1<<8;
+       write_pci_config(num, slot, func, 0x70, d);
+
+       d = read_pci_config(num, slot, func, 0x8);
+       d &= 0xff;
+       return d;
+}
+
+static void __init ati_bugs(int num, int slot, int func)
+{
+#if defined(CONFIG_ACPI) && defined (CONFIG_X86_IO_APIC)
+       u32 d;
+       u8  b;
+
+       if (acpi_use_timer_override)
+               return;
+
+       d = ati_ixp4x0_rev(num, slot, func);
+       if (d  < 0x82)
+               acpi_skip_timer_override = 1;
+       else {
+               /* check for IRQ0 interrupt swap */
+               outb(0x72, 0xcd6); b = inb(0xcd7);
+               if (!(b & 0x2))
+                       acpi_skip_timer_override = 1;
+       }
+
+       if (acpi_skip_timer_override) {
+               printk(KERN_INFO "SB4X0 revision 0x%x\n", d);
+               printk(KERN_INFO "Ignoring ACPI timer override.\n");
+               printk(KERN_INFO "If you got timer trouble "
+                      "try acpi_use_timer_override\n");
+       }
+#endif
+}
+
 #ifdef CONFIG_DMAR
 static void __init intel_g33_dmar(int num, int slot, int func)
 {
@@ -128,6 +174,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_BRIDGE_PCI, PCI_ANY_ID, QFLAG_APPLY_ONCE, via_bugs },
        { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB,
          PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, fix_hypertransport_config },
+       { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS,
+         PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
 #ifdef CONFIG_DMAR
        { PCI_VENDOR_ID_INTEL, 0x29c0,
          PCI_CLASS_BRIDGE_HOST, PCI_ANY_ID, 0, intel_g33_dmar },
index ff9e7350da5484747e1fd86014a51fc3faa84654..34ad997d3834dc773b71ae4f27e18828447d2853 100644 (file)
@@ -3,11 +3,19 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/screen_info.h>
+#include <linux/usb/ch9.h>
+#include <linux/pci_regs.h>
+#include <linux/pci_ids.h>
+#include <linux/errno.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/fcntl.h>
 #include <asm/setup.h>
 #include <xen/hvc-console.h>
+#include <asm/pci-direct.h>
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#include <linux/usb/ehci_def.h>
 
 /* Simple VGA output */
 #define VGABASE                (__ISA_IO_base + 0xb8000)
@@ -78,6 +86,7 @@ static int early_serial_base = 0x3f8;  /* ttyS0 */
 static int early_serial_putc(unsigned char ch)
 {
        unsigned timeout = 0xffff;
+
        while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
                cpu_relax();
        outb(ch, early_serial_base + TXR);
@@ -111,7 +120,7 @@ static __init void early_serial_init(char *s)
                if (!strncmp(s, "0x", 2)) {
                        early_serial_base = simple_strtoul(s, &e, 16);
                } else {
-                       static int bases[] = { 0x3f8, 0x2f8 };
+                       static const int __initconst bases[] = { 0x3f8, 0x2f8 };
 
                        if (!strncmp(s, "ttyS", 4))
                                s += 4;
@@ -151,6 +160,721 @@ static struct console early_serial_console = {
        .index =        -1,
 };
 
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+
+static struct ehci_caps __iomem *ehci_caps;
+static struct ehci_regs __iomem *ehci_regs;
+static struct ehci_dbg_port __iomem *ehci_debug;
+static unsigned int dbgp_endpoint_out;
+
+struct ehci_dev {
+       u32 bus;
+       u32 slot;
+       u32 func;
+};
+
+static struct ehci_dev ehci_dev;
+
+#define USB_DEBUG_DEVNUM 127
+
+#define DBGP_DATA_TOGGLE       0x8800
+
+static inline u32 dbgp_pid_update(u32 x, u32 tok)
+{
+       return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
+}
+
+static inline u32 dbgp_len_update(u32 x, u32 len)
+{
+       return (x & ~0x0f) | (len & 0x0f);
+}
+
+/*
+ * USB Packet IDs (PIDs)
+ */
+
+/* token */
+#define USB_PID_OUT            0xe1
+#define USB_PID_IN             0x69
+#define USB_PID_SOF            0xa5
+#define USB_PID_SETUP          0x2d
+/* handshake */
+#define USB_PID_ACK            0xd2
+#define USB_PID_NAK            0x5a
+#define USB_PID_STALL          0x1e
+#define USB_PID_NYET           0x96
+/* data */
+#define USB_PID_DATA0          0xc3
+#define USB_PID_DATA1          0x4b
+#define USB_PID_DATA2          0x87
+#define USB_PID_MDATA          0x0f
+/* Special */
+#define USB_PID_PREAMBLE       0x3c
+#define USB_PID_ERR            0x3c
+#define USB_PID_SPLIT          0x78
+#define USB_PID_PING           0xb4
+#define USB_PID_UNDEF_0                0xf0
+
+#define USB_PID_DATA_TOGGLE    0x88
+#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
+
+#define PCI_CAP_ID_EHCI_DEBUG  0xa
+
+#define HUB_ROOT_RESET_TIME    50      /* times are in msec */
+#define HUB_SHORT_RESET_TIME   10
+#define HUB_LONG_RESET_TIME    200
+#define HUB_RESET_TIMEOUT      500
+
+#define DBGP_MAX_PACKET                8
+
+static int dbgp_wait_until_complete(void)
+{
+       u32 ctrl;
+       int loop = 0x100000;
+
+       do {
+               ctrl = readl(&ehci_debug->control);
+               /* Stop when the transaction is finished */
+               if (ctrl & DBGP_DONE)
+                       break;
+       } while (--loop > 0);
+
+       if (!loop)
+               return -1;
+
+       /*
+        * Now that we have observed the completed transaction,
+        * clear the done bit.
+        */
+       writel(ctrl | DBGP_DONE, &ehci_debug->control);
+       return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
+}
+
+static void dbgp_mdelay(int ms)
+{
+       int i;
+
+       while (ms--) {
+               for (i = 0; i < 1000; i++)
+                       outb(0x1, 0x80);
+       }
+}
+
+static void dbgp_breath(void)
+{
+       /* Sleep to give the debug port a chance to breathe */
+}
+
+static int dbgp_wait_until_done(unsigned ctrl)
+{
+       u32 pids, lpid;
+       int ret;
+       int loop = 3;
+
+retry:
+       writel(ctrl | DBGP_GO, &ehci_debug->control);
+       ret = dbgp_wait_until_complete();
+       pids = readl(&ehci_debug->pids);
+       lpid = DBGP_PID_GET(pids);
+
+       if (ret < 0)
+               return ret;
+
+       /*
+        * If the port is getting full or it has dropped data
+        * start pacing ourselves, not necessary but it's friendly.
+        */
+       if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
+               dbgp_breath();
+
+       /* If I get a NACK reissue the transmission */
+       if (lpid == USB_PID_NAK) {
+               if (--loop > 0)
+                       goto retry;
+       }
+
+       return ret;
+}
+
+static void dbgp_set_data(const void *buf, int size)
+{
+       const unsigned char *bytes = buf;
+       u32 lo, hi;
+       int i;
+
+       lo = hi = 0;
+       for (i = 0; i < 4 && i < size; i++)
+               lo |= bytes[i] << (8*i);
+       for (; i < 8 && i < size; i++)
+               hi |= bytes[i] << (8*(i - 4));
+       writel(lo, &ehci_debug->data03);
+       writel(hi, &ehci_debug->data47);
+}
+
+static void dbgp_get_data(void *buf, int size)
+{
+       unsigned char *bytes = buf;
+       u32 lo, hi;
+       int i;
+
+       lo = readl(&ehci_debug->data03);
+       hi = readl(&ehci_debug->data47);
+       for (i = 0; i < 4 && i < size; i++)
+               bytes[i] = (lo >> (8*i)) & 0xff;
+       for (; i < 8 && i < size; i++)
+               bytes[i] = (hi >> (8*(i - 4))) & 0xff;
+}
+
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+                        const char *bytes, int size)
+{
+       u32 pids, addr, ctrl;
+       int ret;
+
+       if (size > DBGP_MAX_PACKET)
+               return -1;
+
+       addr = DBGP_EPADDR(devnum, endpoint);
+
+       pids = readl(&ehci_debug->pids);
+       pids = dbgp_pid_update(pids, USB_PID_OUT);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, size);
+       ctrl |= DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       dbgp_set_data(bytes, size);
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
+                                int size)
+{
+       u32 pids, addr, ctrl;
+       int ret;
+
+       if (size > DBGP_MAX_PACKET)
+               return -1;
+
+       addr = DBGP_EPADDR(devnum, endpoint);
+
+       pids = readl(&ehci_debug->pids);
+       pids = dbgp_pid_update(pids, USB_PID_IN);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, size);
+       ctrl &= ~DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       if (size > ret)
+               size = ret;
+       dbgp_get_data(data, size);
+       return ret;
+}
+
+static int dbgp_control_msg(unsigned devnum, int requesttype, int request,
+       int value, int index, void *data, int size)
+{
+       u32 pids, addr, ctrl;
+       struct usb_ctrlrequest req;
+       int read;
+       int ret;
+
+       read = (requesttype & USB_DIR_IN) != 0;
+       if (size > (read ? DBGP_MAX_PACKET:0))
+               return -1;
+
+       /* Compute the control message */
+       req.bRequestType = requesttype;
+       req.bRequest = request;
+       req.wValue = cpu_to_le16(value);
+       req.wIndex = cpu_to_le16(index);
+       req.wLength = cpu_to_le16(size);
+
+       pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
+       addr = DBGP_EPADDR(devnum, 0);
+
+       ctrl = readl(&ehci_debug->control);
+       ctrl = dbgp_len_update(ctrl, sizeof(req));
+       ctrl |= DBGP_OUT;
+       ctrl |= DBGP_GO;
+
+       /* Send the setup message */
+       dbgp_set_data(&req, sizeof(req));
+       writel(addr, &ehci_debug->address);
+       writel(pids, &ehci_debug->pids);
+       ret = dbgp_wait_until_done(ctrl);
+       if (ret < 0)
+               return ret;
+
+       /* Read the result */
+       return dbgp_bulk_read(devnum, 0, data, size);
+}
+
+
+/* Find a PCI capability */
+static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
+{
+       u8 pos;
+       int bytes;
+
+       if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
+               PCI_STATUS_CAP_LIST))
+               return 0;
+
+       pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
+       for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
+               u8 id;
+
+               pos &= ~3;
+               id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
+               if (id == 0xff)
+                       break;
+               if (id == cap)
+                       return pos;
+
+               pos = read_pci_config_byte(num, slot, func,
+                                                pos+PCI_CAP_LIST_NEXT);
+       }
+       return 0;
+}
+
+static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
+{
+       u32 class;
+
+       class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
+       if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
+               return 0;
+
+       return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
+}
+
+static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
+{
+       u32 bus, slot, func;
+
+       for (bus = 0; bus < 256; bus++) {
+               for (slot = 0; slot < 32; slot++) {
+                       for (func = 0; func < 8; func++) {
+                               unsigned cap;
+
+                               cap = __find_dbgp(bus, slot, func);
+
+                               if (!cap)
+                                       continue;
+                               if (ehci_num-- != 0)
+                                       continue;
+                               *rbus = bus;
+                               *rslot = slot;
+                               *rfunc = func;
+                               return cap;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int ehci_reset_port(int port)
+{
+       u32 portsc;
+       u32 delay_time, delay;
+       int loop;
+
+       /* Reset the usb debug port */
+       portsc = readl(&ehci_regs->port_status[port - 1]);
+       portsc &= ~PORT_PE;
+       portsc |= PORT_RESET;
+       writel(portsc, &ehci_regs->port_status[port - 1]);
+
+       delay = HUB_ROOT_RESET_TIME;
+       for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
+            delay_time += delay) {
+               dbgp_mdelay(delay);
+
+               portsc = readl(&ehci_regs->port_status[port - 1]);
+               if (portsc & PORT_RESET) {
+                       /* force reset to complete */
+                       loop = 2;
+                       writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
+                               &ehci_regs->port_status[port - 1]);
+                       do {
+                               portsc = readl(&ehci_regs->port_status[port-1]);
+                       } while ((portsc & PORT_RESET) && (--loop > 0));
+               }
+
+               /* Device went away? */
+               if (!(portsc & PORT_CONNECT))
+                       return -ENOTCONN;
+
+               /* bomb out completely if something weird happend */
+               if ((portsc & PORT_CSC))
+                       return -EINVAL;
+
+               /* If we've finished resetting, then break out of the loop */
+               if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
+                       return 0;
+       }
+       return -EBUSY;
+}
+
+static int ehci_wait_for_port(int port)
+{
+       u32 status;
+       int ret, reps;
+
+       for (reps = 0; reps < 3; reps++) {
+               dbgp_mdelay(100);
+               status = readl(&ehci_regs->status);
+               if (status & STS_PCD) {
+                       ret = ehci_reset_port(port);
+                       if (ret == 0)
+                               return 0;
+               }
+       }
+       return -ENOTCONN;
+}
+
+#ifdef DBGP_DEBUG
+# define dbgp_printk early_printk
+#else
+static inline void dbgp_printk(const char *fmt, ...) { }
+#endif
+
+typedef void (*set_debug_port_t)(int port);
+
+static void default_set_debug_port(int port)
+{
+}
+
+static set_debug_port_t set_debug_port = default_set_debug_port;
+
+static void nvidia_set_debug_port(int port)
+{
+       u32 dword;
+       dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+                                0x74);
+       dword &= ~(0x0f<<12);
+       dword |= ((port & 0x0f)<<12);
+       write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
+                                dword);
+       dbgp_printk("set debug port to %d\n", port);
+}
+
+static void __init detect_set_debug_port(void)
+{
+       u32 vendorid;
+
+       vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
+                0x00);
+
+       if ((vendorid & 0xffff) == 0x10de) {
+               dbgp_printk("using nvidia set_debug_port\n");
+               set_debug_port = nvidia_set_debug_port;
+       }
+}
+
+static int __init ehci_setup(void)
+{
+       struct usb_debug_descriptor dbgp_desc;
+       u32 cmd, ctrl, status, portsc, hcs_params;
+       u32 debug_port, new_debug_port = 0, n_ports;
+       u32  devnum;
+       int ret, i;
+       int loop;
+       int port_map_tried;
+       int playtimes = 3;
+
+try_next_time:
+       port_map_tried = 0;
+
+try_next_port:
+
+       hcs_params = readl(&ehci_caps->hcs_params);
+       debug_port = HCS_DEBUG_PORT(hcs_params);
+       n_ports    = HCS_N_PORTS(hcs_params);
+
+       dbgp_printk("debug_port: %d\n", debug_port);
+       dbgp_printk("n_ports:    %d\n", n_ports);
+
+       for (i = 1; i <= n_ports; i++) {
+               portsc = readl(&ehci_regs->port_status[i-1]);
+               dbgp_printk("portstatus%d: %08x\n", i, portsc);
+       }
+
+       if (port_map_tried && (new_debug_port != debug_port)) {
+               if (--playtimes) {
+                       set_debug_port(new_debug_port);
+                       goto try_next_time;
+               }
+               return -1;
+       }
+
+       loop = 10;
+       /* Reset the EHCI controller */
+       cmd = readl(&ehci_regs->command);
+       cmd |= CMD_RESET;
+       writel(cmd, &ehci_regs->command);
+       do {
+               cmd = readl(&ehci_regs->command);
+       } while ((cmd & CMD_RESET) && (--loop > 0));
+
+       if (!loop) {
+               dbgp_printk("can not reset ehci\n");
+               return -1;
+       }
+       dbgp_printk("ehci reset done\n");
+
+       /* Claim ownership, but do not enable yet */
+       ctrl = readl(&ehci_debug->control);
+       ctrl |= DBGP_OWNER;
+       ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
+       writel(ctrl, &ehci_debug->control);
+
+       /* Start the ehci running */
+       cmd = readl(&ehci_regs->command);
+       cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
+       cmd |= CMD_RUN;
+       writel(cmd, &ehci_regs->command);
+
+       /* Ensure everything is routed to the EHCI */
+       writel(FLAG_CF, &ehci_regs->configured_flag);
+
+       /* Wait until the controller is no longer halted */
+       loop = 10;
+       do {
+               status = readl(&ehci_regs->status);
+       } while ((status & STS_HALT) && (--loop > 0));
+
+       if (!loop) {
+               dbgp_printk("ehci can be started\n");
+               return -1;
+       }
+       dbgp_printk("ehci started\n");
+
+       /* Wait for a device to show up in the debug port */
+       ret = ehci_wait_for_port(debug_port);
+       if (ret < 0) {
+               dbgp_printk("No device found in debug port\n");
+               goto next_debug_port;
+       }
+       dbgp_printk("ehci wait for port done\n");
+
+       /* Enable the debug port */
+       ctrl = readl(&ehci_debug->control);
+       ctrl |= DBGP_CLAIM;
+       writel(ctrl, &ehci_debug->control);
+       ctrl = readl(&ehci_debug->control);
+       if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
+               dbgp_printk("No device in debug port\n");
+               writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
+               goto err;
+       }
+       dbgp_printk("debug ported enabled\n");
+
+       /* Completely transfer the debug device to the debug controller */
+       portsc = readl(&ehci_regs->port_status[debug_port - 1]);
+       portsc &= ~PORT_PE;
+       writel(portsc, &ehci_regs->port_status[debug_port - 1]);
+
+       dbgp_mdelay(100);
+
+       /* Find the debug device and make it device number 127 */
+       for (devnum = 0; devnum <= 127; devnum++) {
+               ret = dbgp_control_msg(devnum,
+                       USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
+                       &dbgp_desc, sizeof(dbgp_desc));
+               if (ret > 0)
+                       break;
+       }
+       if (devnum > 127) {
+               dbgp_printk("Could not find attached debug device\n");
+               goto err;
+       }
+       if (ret < 0) {
+               dbgp_printk("Attached device is not a debug device\n");
+               goto err;
+       }
+       dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
+
+       /* Move the device to 127 if it isn't already there */
+       if (devnum != USB_DEBUG_DEVNUM) {
+               ret = dbgp_control_msg(devnum,
+                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+                       USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
+               if (ret < 0) {
+                       dbgp_printk("Could not move attached device to %d\n",
+                               USB_DEBUG_DEVNUM);
+                       goto err;
+               }
+               devnum = USB_DEBUG_DEVNUM;
+               dbgp_printk("debug device renamed to 127\n");
+       }
+
+       /* Enable the debug interface */
+       ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
+               USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+               USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
+       if (ret < 0) {
+               dbgp_printk(" Could not enable the debug device\n");
+               goto err;
+       }
+       dbgp_printk("debug interface enabled\n");
+
+       /* Perform a small write to get the even/odd data state in sync
+        */
+       ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
+       if (ret < 0) {
+               dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
+               goto err;
+       }
+       dbgp_printk("small write doned\n");
+
+       return 0;
+err:
+       /* Things didn't work so remove my claim */
+       ctrl = readl(&ehci_debug->control);
+       ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
+       writel(ctrl, &ehci_debug->control);
+       return -1;
+
+next_debug_port:
+       port_map_tried |= (1<<(debug_port - 1));
+       new_debug_port = ((debug_port-1+1)%n_ports) + 1;
+       if (port_map_tried != ((1<<n_ports) - 1)) {
+               set_debug_port(new_debug_port);
+               goto try_next_port;
+       }
+       if (--playtimes) {
+               set_debug_port(new_debug_port);
+               goto try_next_time;
+       }
+
+       return -1;
+}
+
+static int __init early_dbgp_init(char *s)
+{
+       u32 debug_port, bar, offset;
+       u32 bus, slot, func, cap;
+       void __iomem *ehci_bar;
+       u32 dbgp_num;
+       u32 bar_val;
+       char *e;
+       int ret;
+       u8 byte;
+
+       if (!early_pci_allowed())
+               return -1;
+
+       dbgp_num = 0;
+       if (*s)
+               dbgp_num = simple_strtoul(s, &e, 10);
+       dbgp_printk("dbgp_num: %d\n", dbgp_num);
+
+       cap = find_dbgp(dbgp_num, &bus, &slot, &func);
+       if (!cap)
+               return -1;
+
+       dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
+                        func);
+
+       debug_port = read_pci_config(bus, slot, func, cap);
+       bar = (debug_port >> 29) & 0x7;
+       bar = (bar * 4) + 0xc;
+       offset = (debug_port >> 16) & 0xfff;
+       dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
+       if (bar != PCI_BASE_ADDRESS_0) {
+               dbgp_printk("only debug ports on bar 1 handled.\n");
+
+               return -1;
+       }
+
+       bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
+       dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
+       if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
+               dbgp_printk("only simple 32bit mmio bars supported\n");
+
+               return -1;
+       }
+
+       /* double check if the mem space is enabled */
+       byte = read_pci_config_byte(bus, slot, func, 0x04);
+       if (!(byte & 0x2)) {
+               byte  |= 0x02;
+               write_pci_config_byte(bus, slot, func, 0x04, byte);
+               dbgp_printk("mmio for ehci enabled\n");
+       }
+
+       /*
+        * FIXME I don't have the bar size so just guess PAGE_SIZE is more
+        * than enough.  1K is the biggest I have seen.
+        */
+       set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
+       ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
+       ehci_bar += bar_val & ~PAGE_MASK;
+       dbgp_printk("ehci_bar: %p\n", ehci_bar);
+
+       ehci_caps  = ehci_bar;
+       ehci_regs  = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
+       ehci_debug = ehci_bar + offset;
+       ehci_dev.bus = bus;
+       ehci_dev.slot = slot;
+       ehci_dev.func = func;
+
+       detect_set_debug_port();
+
+       ret = ehci_setup();
+       if (ret < 0) {
+               dbgp_printk("ehci_setup failed\n");
+               ehci_debug = NULL;
+
+               return -1;
+       }
+
+       return 0;
+}
+
+static void early_dbgp_write(struct console *con, const char *str, u32 n)
+{
+       int chunk, ret;
+
+       if (!ehci_debug)
+               return;
+       while (n > 0) {
+               chunk = n;
+               if (chunk > DBGP_MAX_PACKET)
+                       chunk = DBGP_MAX_PACKET;
+               ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
+                       dbgp_endpoint_out, str, chunk);
+               str += chunk;
+               n -= chunk;
+       }
+}
+
+static struct console early_dbgp_console = {
+       .name =         "earlydbg",
+       .write =        early_dbgp_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
+#endif
+
 /* Console interface to a host file on AMD's SimNow! */
 
 static int simnow_fd;
@@ -165,6 +889,7 @@ enum {
 static noinline long simnow(long cmd, long a, long b, long c)
 {
        long ret;
+
        asm volatile("cpuid" :
                     "=a" (ret) :
                     "b" (a), "c" (b), "d" (c), "0" (MAGIC1), "D" (cmd + MAGIC2));
@@ -174,6 +899,7 @@ static noinline long simnow(long cmd, long a, long b, long c)
 static void __init simnow_init(char *str)
 {
        char *fn = "klog";
+
        if (*str == '=')
                fn = ++str;
        /* error ignored */
@@ -194,7 +920,7 @@ static struct console simnow_console = {
 
 /* Direct interface for emergencies */
 static struct console *early_console = &early_vga_console;
-static int early_console_initialized;
+static int __initdata early_console_initialized;
 
 asmlinkage void early_printk(const char *fmt, ...)
 {
@@ -208,10 +934,11 @@ asmlinkage void early_printk(const char *fmt, ...)
        va_end(ap);
 }
 
-static int __initdata keep_early;
 
 static int __init setup_early_printk(char *buf)
 {
+       int keep_early;
+
        if (!buf)
                return 0;
 
@@ -219,8 +946,7 @@ static int __init setup_early_printk(char *buf)
                return 0;
        early_console_initialized = 1;
 
-       if (strstr(buf, "keep"))
-               keep_early = 1;
+       keep_early = (strstr(buf, "keep") != NULL);
 
        if (!strncmp(buf, "serial", 6)) {
                early_serial_init(buf + 6);
@@ -238,6 +964,17 @@ static int __init setup_early_printk(char *buf)
                simnow_init(buf + 6);
                early_console = &simnow_console;
                keep_early = 1;
+#ifdef CONFIG_EARLY_PRINTK_DBGP
+       } else if (!strncmp(buf, "dbgp", 4)) {
+               if (early_dbgp_init(buf+4) < 0)
+                       return 0;
+               early_console = &early_dbgp_console;
+               /*
+                * usb subsys will reset ehci controller, so don't keep
+                * that early console
+                */
+               keep_early = 0;
+#endif
 #ifdef CONFIG_HVC_XEN
        } else if (!strncmp(buf, "xen", 3)) {
                early_console = &xenboot_console;
@@ -251,4 +988,5 @@ static int __init setup_early_printk(char *buf)
        register_console(early_console);
        return 0;
 }
+
 early_param("earlyprintk", setup_early_printk);
index 45723f1fe198bec671ba5f7001b1d61ef5e671be..1f20608d4ca8b6e274518715ef487933e8489c59 100644 (file)
@@ -468,9 +468,23 @@ static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
 
 static int save_i387_xsave(void __user *buf)
 {
+       struct task_struct *tsk = current;
        struct _fpstate_ia32 __user *fx = buf;
        int err = 0;
 
+       /*
+        * For legacy compatible, we always set FP/SSE bits in the bit
+        * vector while saving the state to the user context.
+        * This will enable us capturing any changes(during sigreturn) to
+        * the FP/SSE bits by the legacy applications which don't touch
+        * xstate_bv in the xsave header.
+        *
+        * xsave aware applications can change the xstate_bv in the xsave
+        * header as well as change any contents in the memory layout.
+        * xrestore as part of sigreturn will capture all the changes.
+        */
+       tsk->thread.xstate->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
+
        if (save_i387_fxsave(fx) < 0)
                return -1;
 
index a1bec2969c6af666d9566ba9a3ba5bcef0a34ee0..02063ae042f72ae979a13b57035bd0d91f1dcb59 100644 (file)
@@ -1281,8 +1281,8 @@ __apicdebuginit(void) print_local_APIC(void *dummy)
        printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
 
        icr = apic_icr_read();
-       printk(KERN_DEBUG "... APIC ICR: %08x\n", icr);
-       printk(KERN_DEBUG "... APIC ICR2: %08x\n", icr >> 32);
+       printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
+       printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
 
        v = apic_read(APIC_LVTT);
        printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
index 0ed5f939b9056330cb0eb5eaefe564f405b4a14a..eee32b43fee3e59b5ab8e3a2243bb6f6a56fb21e 100644 (file)
@@ -52,6 +52,8 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
        memset(newldt + oldsize * LDT_ENTRY_SIZE, 0,
               (mincount - oldsize) * LDT_ENTRY_SIZE);
 
+       paravirt_alloc_ldt(newldt, mincount);
+
 #ifdef CONFIG_X86_64
        /* CHECKME: Do we really need this ? */
        wmb();
@@ -74,6 +76,7 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 #endif
        }
        if (oldsize) {
+               paravirt_free_ldt(oldldt, oldsize);
                if (oldsize * LDT_ENTRY_SIZE > PAGE_SIZE)
                        vfree(oldldt);
                else
@@ -85,10 +88,13 @@ static int alloc_ldt(mm_context_t *pc, int mincount, int reload)
 static inline int copy_ldt(mm_context_t *new, mm_context_t *old)
 {
        int err = alloc_ldt(new, old->size, 0);
+       int i;
 
        if (err < 0)
                return err;
-       memcpy(new->ldt, old->ldt, old->size * LDT_ENTRY_SIZE);
+
+       for(i = 0; i < old->size; i++)
+               write_ldt_entry(new->ldt, i, old->ldt + i * LDT_ENTRY_SIZE);
        return 0;
 }
 
@@ -125,6 +131,7 @@ void destroy_context(struct mm_struct *mm)
                if (mm == current->active_mm)
                        clear_LDT();
 #endif
+               paravirt_free_ldt(mm->context.ldt, mm->context.size);
                if (mm->context.size * LDT_ENTRY_SIZE > PAGE_SIZE)
                        vfree(mm->context.ldt);
                else
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
deleted file mode 100644 (file)
index 652fa5c..0000000
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- *     Intel CPU Microcode Update Driver for Linux
- *
- *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
- *                   2006      Shaohua Li <shaohua.li@intel.com>
- *
- *     This driver allows to upgrade microcode on Intel processors
- *     belonging to IA-32 family - PentiumPro, Pentium II,
- *     Pentium III, Xeon, Pentium 4, etc.
- *
- *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
- *     Software Developer's Manual
- *     Order Number 253668 or free download from:
- *
- *     http://developer.intel.com/design/pentium4/manuals/253668.htm
- *
- *     For more information, go to http://www.urbanmyth.org/microcode
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License
- *     as published by the Free Software Foundation; either version
- *     2 of the License, or (at your option) any later version.
- *
- *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Initial release.
- *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Added read() support + cleanups.
- *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Added 'device trimming' support. open(O_WRONLY) zeroes
- *             and frees the saved copy of applied microcode.
- *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
- *             Made to use devfs (/dev/cpu/microcode) + cleanups.
- *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
- *             Added misc device support (now uses both devfs and misc).
- *             Added MICROCODE_IOCFREE ioctl to clear memory.
- *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
- *             Messages for error cases (non Intel & no suitable microcode).
- *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
- *             Removed ->release(). Removed exclusive open and status bitmap.
- *             Added microcode_rwsem to serialize read()/write()/ioctl().
- *             Removed global kernel lock usage.
- *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
- *             Write 0 to 0x8B msr and then cpuid before reading revision,
- *             so that it works even if there were no update done by the
- *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
- *             to be 0 on my machine which is why it worked even when I
- *             disabled update by the BIOS)
- *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
- *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
- *                          Tigran Aivazian <tigran@veritas.com>
- *             Intel Pentium 4 processor support and bugfixes.
- *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
- *             Bugfix for HT (Hyper-Threading) enabled processors
- *             whereby processor resources are shared by all logical processors
- *             in a single CPU package.
- *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
- *             Tigran Aivazian <tigran@veritas.com>,
- *             Serialize updates as required on HT processors due to speculative
- *             nature of implementation.
- *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
- *             Fix the panic when writing zero-length microcode chunk.
- *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
- *             Jun Nakajima <jun.nakajima@intel.com>
- *             Support for the microcode updates in the new format.
- *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
- *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
- *             because we no longer hold a copy of applied microcode
- *             in kernel memory.
- *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
- *             Fix sigmatch() macro to handle old CPUs with pf == 0.
- *             Thanks to Stuart Swales for pointing out this bug.
- */
-
-//#define DEBUG /* pr_debug */
-#include <linux/capability.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/cpumask.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/mutex.h>
-#include <linux/cpu.h>
-#include <linux/firmware.h>
-#include <linux/platform_device.h>
-
-#include <asm/msr.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
-MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
-MODULE_LICENSE("GPL");
-
-#define MICROCODE_VERSION      "1.14a"
-
-#define DEFAULT_UCODE_DATASIZE         (2000)    /* 2000 bytes */
-#define MC_HEADER_SIZE         (sizeof (microcode_header_t))     /* 48 bytes */
-#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE) /* 2048 bytes */
-#define EXT_HEADER_SIZE                (sizeof (struct extended_sigtable)) /* 20 bytes */
-#define EXT_SIGNATURE_SIZE     (sizeof (struct extended_signature)) /* 12 bytes */
-#define DWSIZE                 (sizeof (u32))
-#define get_totalsize(mc) \
-       (((microcode_t *)mc)->hdr.totalsize ? \
-        ((microcode_t *)mc)->hdr.totalsize : DEFAULT_UCODE_TOTALSIZE)
-#define get_datasize(mc) \
-       (((microcode_t *)mc)->hdr.datasize ? \
-        ((microcode_t *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
-
-#define sigmatch(s1, s2, p1, p2) \
-       (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
-
-#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
-
-/* serialize access to the physical write to MSR 0x79 */
-static DEFINE_SPINLOCK(microcode_update_lock);
-
-/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
-static DEFINE_MUTEX(microcode_mutex);
-
-static struct ucode_cpu_info {
-       int valid;
-       unsigned int sig;
-       unsigned int pf;
-       unsigned int rev;
-       microcode_t *mc;
-} ucode_cpu_info[NR_CPUS];
-
-static void collect_cpu_info(int cpu_num)
-{
-       struct cpuinfo_x86 *c = &cpu_data(cpu_num);
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-       unsigned int val[2];
-
-       /* We should bind the task to the CPU */
-       BUG_ON(raw_smp_processor_id() != cpu_num);
-       uci->pf = uci->rev = 0;
-       uci->mc = NULL;
-       uci->valid = 1;
-
-       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-               cpu_has(c, X86_FEATURE_IA64)) {
-               printk(KERN_ERR "microcode: CPU%d not a capable Intel "
-                       "processor\n", cpu_num);
-               uci->valid = 0;
-               return;
-       }
-
-       uci->sig = cpuid_eax(0x00000001);
-
-       if ((c->x86_model >= 5) || (c->x86 > 6)) {
-               /* get processor flags from MSR 0x17 */
-               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-               uci->pf = 1 << ((val[1] >> 18) & 7);
-       }
-
-       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-       /* see notes above for revision 1.07.  Apparent chip bug */
-       sync_core();
-       /* get the current revision from MSR 0x8B */
-       rdmsr(MSR_IA32_UCODE_REV, val[0], uci->rev);
-       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
-                       uci->sig, uci->pf, uci->rev);
-}
-
-static inline int microcode_update_match(int cpu_num,
-       microcode_header_t *mc_header, int sig, int pf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-       if (!sigmatch(sig, uci->sig, pf, uci->pf)
-               || mc_header->rev <= uci->rev)
-               return 0;
-       return 1;
-}
-
-static int microcode_sanity_check(void *mc)
-{
-       microcode_header_t *mc_header = mc;
-       struct extended_sigtable *ext_header = NULL;
-       struct extended_signature *ext_sig;
-       unsigned long total_size, data_size, ext_table_size;
-       int sum, orig_sum, ext_sigcount = 0, i;
-
-       total_size = get_totalsize(mc_header);
-       data_size = get_datasize(mc_header);
-       if (data_size + MC_HEADER_SIZE > total_size) {
-               printk(KERN_ERR "microcode: error! "
-                       "Bad data size in microcode data file\n");
-               return -EINVAL;
-       }
-
-       if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
-               printk(KERN_ERR "microcode: error! "
-                       "Unknown microcode update format\n");
-               return -EINVAL;
-       }
-       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
-       if (ext_table_size) {
-               if ((ext_table_size < EXT_HEADER_SIZE)
-                || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
-                       printk(KERN_ERR "microcode: error! "
-                               "Small exttable size in microcode data file\n");
-                       return -EINVAL;
-               }
-               ext_header = mc + MC_HEADER_SIZE + data_size;
-               if (ext_table_size != exttable_size(ext_header)) {
-                       printk(KERN_ERR "microcode: error! "
-                               "Bad exttable size in microcode data file\n");
-                       return -EFAULT;
-               }
-               ext_sigcount = ext_header->count;
-       }
-
-       /* check extended table checksum */
-       if (ext_table_size) {
-               int ext_table_sum = 0;
-               int *ext_tablep = (int *)ext_header;
-
-               i = ext_table_size / DWSIZE;
-               while (i--)
-                       ext_table_sum += ext_tablep[i];
-               if (ext_table_sum) {
-                       printk(KERN_WARNING "microcode: aborting, "
-                               "bad extended signature table checksum\n");
-                       return -EINVAL;
-               }
-       }
-
-       /* calculate the checksum */
-       orig_sum = 0;
-       i = (MC_HEADER_SIZE + data_size) / DWSIZE;
-       while (i--)
-               orig_sum += ((int *)mc)[i];
-       if (orig_sum) {
-               printk(KERN_ERR "microcode: aborting, bad checksum\n");
-               return -EINVAL;
-       }
-       if (!ext_table_size)
-               return 0;
-       /* check extended signature checksum */
-       for (i = 0; i < ext_sigcount; i++) {
-               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
-                         EXT_SIGNATURE_SIZE * i;
-               sum = orig_sum
-                       - (mc_header->sig + mc_header->pf + mc_header->cksum)
-                       + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
-               if (sum) {
-                       printk(KERN_ERR "microcode: aborting, bad checksum\n");
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-
-/*
- * return 0 - no update found
- * return 1 - found update
- * return < 0 - error
- */
-static int get_maching_microcode(void *mc, int cpu)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       microcode_header_t *mc_header = mc;
-       struct extended_sigtable *ext_header;
-       unsigned long total_size = get_totalsize(mc_header);
-       int ext_sigcount, i;
-       struct extended_signature *ext_sig;
-       void *new_mc;
-
-       if (microcode_update_match(cpu, mc_header,
-                       mc_header->sig, mc_header->pf))
-               goto find;
-
-       if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
-               return 0;
-
-       ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
-       ext_sigcount = ext_header->count;
-       ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
-       for (i = 0; i < ext_sigcount; i++) {
-               if (microcode_update_match(cpu, mc_header,
-                               ext_sig->sig, ext_sig->pf))
-                       goto find;
-               ext_sig++;
-       }
-       return 0;
-find:
-       pr_debug("microcode: CPU%d found a matching microcode update with"
-               " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
-       new_mc = vmalloc(total_size);
-       if (!new_mc) {
-               printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-               return -ENOMEM;
-       }
-
-       /* free previous update file */
-       vfree(uci->mc);
-
-       memcpy(new_mc, mc, total_size);
-       uci->mc = new_mc;
-       return 1;
-}
-
-static void apply_microcode(int cpu)
-{
-       unsigned long flags;
-       unsigned int val[2];
-       int cpu_num = raw_smp_processor_id();
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu_num != cpu);
-
-       if (uci->mc == NULL)
-               return;
-
-       /* serialize access to the physical write to MSR 0x79 */
-       spin_lock_irqsave(&microcode_update_lock, flags);
-
-       /* write microcode via MSR 0x79 */
-       wrmsr(MSR_IA32_UCODE_WRITE,
-               (unsigned long) uci->mc->bits,
-               (unsigned long) uci->mc->bits >> 16 >> 16);
-       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-
-       /* see notes above for revision 1.07.  Apparent chip bug */
-       sync_core();
-
-       /* get the current revision from MSR 0x8B */
-       rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-
-       spin_unlock_irqrestore(&microcode_update_lock, flags);
-       if (val[1] != uci->mc->hdr.rev) {
-               printk(KERN_ERR "microcode: CPU%d update from revision "
-                       "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
-               return;
-       }
-       printk(KERN_INFO "microcode: CPU%d updated from revision "
-              "0x%x to 0x%x, date = %08x \n",
-              cpu_num, uci->rev, val[1], uci->mc->hdr.date);
-       uci->rev = val[1];
-}
-
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static void __user *user_buffer;       /* user area microcode data buffer */
-static unsigned int user_buffer_size;  /* it's size */
-
-static long get_next_ucode(void **mc, long offset)
-{
-       microcode_header_t mc_header;
-       unsigned long total_size;
-
-       /* No more data */
-       if (offset >= user_buffer_size)
-               return 0;
-       if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
-               printk(KERN_ERR "microcode: error! Can not read user data\n");
-               return -EFAULT;
-       }
-       total_size = get_totalsize(&mc_header);
-       if (offset + total_size > user_buffer_size) {
-               printk(KERN_ERR "microcode: error! Bad total size in microcode "
-                               "data file\n");
-               return -EINVAL;
-       }
-       *mc = vmalloc(total_size);
-       if (!*mc)
-               return -ENOMEM;
-       if (copy_from_user(*mc, user_buffer + offset, total_size)) {
-               printk(KERN_ERR "microcode: error! Can not read user data\n");
-               vfree(*mc);
-               return -EFAULT;
-       }
-       return offset + total_size;
-}
-
-static int do_microcode_update (void)
-{
-       long cursor = 0;
-       int error = 0;
-       void *new_mc = NULL;
-       int cpu;
-       cpumask_t old;
-
-       old = current->cpus_allowed;
-
-       while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
-               error = microcode_sanity_check(new_mc);
-               if (error)
-                       goto out;
-               /*
-                * It's possible the data file has multiple matching ucode,
-                * lets keep searching till the latest version
-                */
-               for_each_online_cpu(cpu) {
-                       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-                       if (!uci->valid)
-                               continue;
-                       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-                       error = get_maching_microcode(new_mc, cpu);
-                       if (error < 0)
-                               goto out;
-                       if (error == 1)
-                               apply_microcode(cpu);
-               }
-               vfree(new_mc);
-       }
-out:
-       if (cursor > 0)
-               vfree(new_mc);
-       if (cursor < 0)
-               error = cursor;
-       set_cpus_allowed_ptr(current, &old);
-       return error;
-}
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
-       cycle_kernel_lock();
-       return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-
-static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
-{
-       ssize_t ret;
-
-       if ((len >> PAGE_SHIFT) > num_physpages) {
-               printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
-               return -EINVAL;
-       }
-
-       get_online_cpus();
-       mutex_lock(&microcode_mutex);
-
-       user_buffer = (void __user *) buf;
-       user_buffer_size = (int) len;
-
-       ret = do_microcode_update();
-       if (!ret)
-               ret = (ssize_t)len;
-
-       mutex_unlock(&microcode_mutex);
-       put_online_cpus();
-
-       return ret;
-}
-
-static const struct file_operations microcode_fops = {
-       .owner          = THIS_MODULE,
-       .write          = microcode_write,
-       .open           = microcode_open,
-};
-
-static struct miscdevice microcode_dev = {
-       .minor          = MICROCODE_MINOR,
-       .name           = "microcode",
-       .fops           = &microcode_fops,
-};
-
-static int __init microcode_dev_init (void)
-{
-       int error;
-
-       error = misc_register(&microcode_dev);
-       if (error) {
-               printk(KERN_ERR
-                       "microcode: can't misc_register on minor=%d\n",
-                       MICROCODE_MINOR);
-               return error;
-       }
-
-       return 0;
-}
-
-static void microcode_dev_exit (void)
-{
-       misc_deregister(&microcode_dev);
-}
-
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while(0)
-#endif
-
-static long get_next_ucode_from_buffer(void **mc, const u8 *buf,
-       unsigned long size, long offset)
-{
-       microcode_header_t *mc_header;
-       unsigned long total_size;
-
-       /* No more data */
-       if (offset >= size)
-               return 0;
-       mc_header = (microcode_header_t *)(buf + offset);
-       total_size = get_totalsize(mc_header);
-
-       if (offset + total_size > size) {
-               printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
-               return -EINVAL;
-       }
-
-       *mc = vmalloc(total_size);
-       if (!*mc) {
-               printk(KERN_ERR "microcode: error! Can not allocate memory\n");
-               return -ENOMEM;
-       }
-       memcpy(*mc, buf + offset, total_size);
-       return offset + total_size;
-}
-
-/* fake device for request_firmware */
-static struct platform_device *microcode_pdev;
-
-static int cpu_request_microcode(int cpu)
-{
-       char name[30];
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       const struct firmware *firmware;
-       const u8 *buf;
-       unsigned long size;
-       long offset = 0;
-       int error;
-       void *mc;
-
-       /* We should bind the task to the CPU */
-       BUG_ON(cpu != raw_smp_processor_id());
-       sprintf(name,"intel-ucode/%02x-%02x-%02x",
-               c->x86, c->x86_model, c->x86_mask);
-       error = request_firmware(&firmware, name, &microcode_pdev->dev);
-       if (error) {
-               pr_debug("microcode: data file %s load failed\n", name);
-               return error;
-       }
-       buf = firmware->data;
-       size = firmware->size;
-       while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
-                       > 0) {
-               error = microcode_sanity_check(mc);
-               if (error)
-                       break;
-               error = get_maching_microcode(mc, cpu);
-               if (error < 0)
-                       break;
-               /*
-                * It's possible the data file has multiple matching ucode,
-                * lets keep searching till the latest version
-                */
-               if (error == 1) {
-                       apply_microcode(cpu);
-                       error = 0;
-               }
-               vfree(mc);
-       }
-       if (offset > 0)
-               vfree(mc);
-       if (offset < 0)
-               error = offset;
-       release_firmware(firmware);
-
-       return error;
-}
-
-static int apply_microcode_check_cpu(int cpu)
-{
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       cpumask_t old;
-       unsigned int val[2];
-       int err = 0;
-
-       /* Check if the microcode is available */
-       if (!uci->mc)
-               return 0;
-
-       old = current->cpus_allowed;
-       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-       /* Check if the microcode we have in memory matches the CPU */
-       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
-           cpu_has(c, X86_FEATURE_IA64) || uci->sig != cpuid_eax(0x00000001))
-               err = -EINVAL;
-
-       if (!err && ((c->x86_model >= 5) || (c->x86 > 6))) {
-               /* get processor flags from MSR 0x17 */
-               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
-               if (uci->pf != (1 << ((val[1] >> 18) & 7)))
-                       err = -EINVAL;
-       }
-
-       if (!err) {
-               wrmsr(MSR_IA32_UCODE_REV, 0, 0);
-               /* see notes above for revision 1.07.  Apparent chip bug */
-               sync_core();
-               /* get the current revision from MSR 0x8B */
-               rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
-               if (uci->rev != val[1])
-                       err = -EINVAL;
-       }
-
-       if (!err)
-               apply_microcode(cpu);
-       else
-               printk(KERN_ERR "microcode: Could not apply microcode to CPU%d:"
-                       " sig=0x%x, pf=0x%x, rev=0x%x\n",
-                       cpu, uci->sig, uci->pf, uci->rev);
-
-       set_cpus_allowed_ptr(current, &old);
-       return err;
-}
-
-static void microcode_init_cpu(int cpu, int resume)
-{
-       cpumask_t old;
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       old = current->cpus_allowed;
-
-       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-       mutex_lock(&microcode_mutex);
-       collect_cpu_info(cpu);
-       if (uci->valid && system_state == SYSTEM_RUNNING && !resume)
-               cpu_request_microcode(cpu);
-       mutex_unlock(&microcode_mutex);
-       set_cpus_allowed_ptr(current, &old);
-}
-
-static void microcode_fini_cpu(int cpu)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       mutex_lock(&microcode_mutex);
-       uci->valid = 0;
-       vfree(uci->mc);
-       uci->mc = NULL;
-       mutex_unlock(&microcode_mutex);
-}
-
-static ssize_t reload_store(struct sys_device *dev,
-                           struct sysdev_attribute *attr,
-                           const char *buf, size_t sz)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-       char *end;
-       unsigned long val = simple_strtoul(buf, &end, 0);
-       int err = 0;
-       int cpu = dev->id;
-
-       if (end == buf)
-               return -EINVAL;
-       if (val == 1) {
-               cpumask_t old = current->cpus_allowed;
-
-               get_online_cpus();
-               set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
-
-               mutex_lock(&microcode_mutex);
-               if (uci->valid)
-                       err = cpu_request_microcode(cpu);
-               mutex_unlock(&microcode_mutex);
-               put_online_cpus();
-               set_cpus_allowed_ptr(current, &old);
-       }
-       if (err)
-               return err;
-       return sz;
-}
-
-static ssize_t version_show(struct sys_device *dev,
-                       struct sysdev_attribute *attr, char *buf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-       return sprintf(buf, "0x%x\n", uci->rev);
-}
-
-static ssize_t pf_show(struct sys_device *dev,
-                       struct sysdev_attribute *attr, char *buf)
-{
-       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
-
-       return sprintf(buf, "0x%x\n", uci->pf);
-}
-
-static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
-static SYSDEV_ATTR(version, 0400, version_show, NULL);
-static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
-
-static struct attribute *mc_default_attrs[] = {
-       &attr_reload.attr,
-       &attr_version.attr,
-       &attr_processor_flags.attr,
-       NULL
-};
-
-static struct attribute_group mc_attr_group = {
-       .attrs = mc_default_attrs,
-       .name = "microcode",
-};
-
-static int __mc_sysdev_add(struct sys_device *sys_dev, int resume)
-{
-       int err, cpu = sys_dev->id;
-       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-
-       if (!cpu_online(cpu))
-               return 0;
-
-       pr_debug("microcode: CPU%d added\n", cpu);
-       memset(uci, 0, sizeof(*uci));
-
-       err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
-       if (err)
-               return err;
-
-       microcode_init_cpu(cpu, resume);
-
-       return 0;
-}
-
-static int mc_sysdev_add(struct sys_device *sys_dev)
-{
-       return __mc_sysdev_add(sys_dev, 0);
-}
-
-static int mc_sysdev_remove(struct sys_device *sys_dev)
-{
-       int cpu = sys_dev->id;
-
-       if (!cpu_online(cpu))
-               return 0;
-
-       pr_debug("microcode: CPU%d removed\n", cpu);
-       microcode_fini_cpu(cpu);
-       sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-       return 0;
-}
-
-static int mc_sysdev_resume(struct sys_device *dev)
-{
-       int cpu = dev->id;
-
-       if (!cpu_online(cpu))
-               return 0;
-       pr_debug("microcode: CPU%d resumed\n", cpu);
-       /* only CPU 0 will apply ucode here */
-       apply_microcode(0);
-       return 0;
-}
-
-static struct sysdev_driver mc_sysdev_driver = {
-       .add = mc_sysdev_add,
-       .remove = mc_sysdev_remove,
-       .resume = mc_sysdev_resume,
-};
-
-static __cpuinit int
-mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
-{
-       unsigned int cpu = (unsigned long)hcpu;
-       struct sys_device *sys_dev;
-
-       sys_dev = get_cpu_sysdev(cpu);
-       switch (action) {
-       case CPU_UP_CANCELED_FROZEN:
-               /* The CPU refused to come up during a system resume */
-               microcode_fini_cpu(cpu);
-               break;
-       case CPU_ONLINE:
-       case CPU_DOWN_FAILED:
-               mc_sysdev_add(sys_dev);
-               break;
-       case CPU_ONLINE_FROZEN:
-               /* System-wide resume is in progress, try to apply microcode */
-               if (apply_microcode_check_cpu(cpu)) {
-                       /* The application of microcode failed */
-                       microcode_fini_cpu(cpu);
-                       __mc_sysdev_add(sys_dev, 1);
-                       break;
-               }
-       case CPU_DOWN_FAILED_FROZEN:
-               if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
-                       printk(KERN_ERR "microcode: Failed to create the sysfs "
-                               "group for CPU%d\n", cpu);
-               break;
-       case CPU_DOWN_PREPARE:
-               mc_sysdev_remove(sys_dev);
-               break;
-       case CPU_DOWN_PREPARE_FROZEN:
-               /* Suspend is in progress, only remove the interface */
-               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __refdata mc_cpu_notifier = {
-       .notifier_call = mc_cpu_callback,
-};
-
-static int __init microcode_init (void)
-{
-       int error;
-
-       printk(KERN_INFO
-               "IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@aivazian.fsnet.co.uk>\n");
-
-       error = microcode_dev_init();
-       if (error)
-               return error;
-       microcode_pdev = platform_device_register_simple("microcode", -1,
-                                                        NULL, 0);
-       if (IS_ERR(microcode_pdev)) {
-               microcode_dev_exit();
-               return PTR_ERR(microcode_pdev);
-       }
-
-       get_online_cpus();
-       error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
-       put_online_cpus();
-       if (error) {
-               microcode_dev_exit();
-               platform_device_unregister(microcode_pdev);
-               return error;
-       }
-
-       register_hotcpu_notifier(&mc_cpu_notifier);
-       return 0;
-}
-
-static void __exit microcode_exit (void)
-{
-       microcode_dev_exit();
-
-       unregister_hotcpu_notifier(&mc_cpu_notifier);
-
-       get_online_cpus();
-       sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
-       put_online_cpus();
-
-       platform_device_unregister(microcode_pdev);
-}
-
-module_init(microcode_init)
-module_exit(microcode_exit)
diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c
new file mode 100644 (file)
index 0000000..7a1f8ee
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ *  AMD CPU Microcode Update Driver for Linux
+ *  Copyright (C) 2008 Advanced Micro Devices Inc.
+ *
+ *  Author: Peter Oruba <peter.oruba@amd.com>
+ *
+ *  Based on work by:
+ *  Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *
+ *  This driver allows to upgrade microcode on AMD
+ *  family 0x10 and 0x11 processors.
+ *
+ *  Licensed unter the terms of the GNU General Public
+ *  License version 2. See file COPYING for details.
+*/
+
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("AMD Microcode Update Driver");
+MODULE_AUTHOR("Peter Oruba <peter.oruba@amd.com>");
+MODULE_LICENSE("GPL v2");
+
+#define UCODE_MAGIC                0x00414d44
+#define UCODE_EQUIV_CPU_TABLE_TYPE 0x00000000
+#define UCODE_UCODE_TYPE           0x00000001
+
+struct equiv_cpu_entry {
+       unsigned int installed_cpu;
+       unsigned int fixed_errata_mask;
+       unsigned int fixed_errata_compare;
+       unsigned int equiv_cpu;
+};
+
+struct microcode_header_amd {
+       unsigned int  data_code;
+       unsigned int  patch_id;
+       unsigned char mc_patch_data_id[2];
+       unsigned char mc_patch_data_len;
+       unsigned char init_flag;
+       unsigned int  mc_patch_data_checksum;
+       unsigned int  nb_dev_id;
+       unsigned int  sb_dev_id;
+       unsigned char processor_rev_id[2];
+       unsigned char nb_rev_id;
+       unsigned char sb_rev_id;
+       unsigned char bios_api_rev;
+       unsigned char reserved1[3];
+       unsigned int  match_reg[8];
+};
+
+struct microcode_amd {
+       struct microcode_header_amd hdr;
+       unsigned int mpb[0];
+};
+
+#define UCODE_MAX_SIZE          (2048)
+#define DEFAULT_UCODE_DATASIZE (896)
+#define MC_HEADER_SIZE         (sizeof(struct microcode_header_amd))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define DWSIZE                 (sizeof(u32))
+/* For now we support a fixed ucode total size only */
+#define get_totalsize(mc) \
+       ((((struct microcode_amd *)mc)->hdr.mc_patch_data_len * 28) \
+        + MC_HEADER_SIZE)
+
+/* serialize access to the physical write */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static struct equiv_cpu_entry *equiv_cpu_table;
+
+static int collect_cpu_info_amd(int cpu, struct cpu_signature *csig)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+
+       memset(csig, 0, sizeof(*csig));
+
+       if (c->x86_vendor != X86_VENDOR_AMD || c->x86 < 0x10) {
+               printk(KERN_ERR "microcode: CPU%d not a capable AMD processor\n",
+                      cpu);
+               return -1;
+       }
+
+       asm volatile("movl %1, %%ecx; rdmsr"
+                    : "=a" (csig->rev)
+                    : "i" (0x0000008B) : "ecx");
+
+       printk(KERN_INFO "microcode: collect_cpu_info_amd : patch_id=0x%x\n",
+               csig->rev);
+
+       return 0;
+}
+
+static int get_matching_microcode(int cpu, void *mc, int rev)
+{
+       struct microcode_header_amd *mc_header = mc;
+       struct pci_dev *nb_pci_dev, *sb_pci_dev;
+       unsigned int current_cpu_id;
+       unsigned int equiv_cpu_id = 0x00;
+       unsigned int i = 0;
+
+       BUG_ON(equiv_cpu_table == NULL);
+       current_cpu_id = cpuid_eax(0x00000001);
+
+       while (equiv_cpu_table[i].installed_cpu != 0) {
+               if (current_cpu_id == equiv_cpu_table[i].installed_cpu) {
+                       equiv_cpu_id = equiv_cpu_table[i].equiv_cpu;
+                       break;
+               }
+               i++;
+       }
+
+       if (!equiv_cpu_id) {
+               printk(KERN_ERR "microcode: CPU%d cpu_id "
+                      "not found in equivalent cpu table \n", cpu);
+               return 0;
+       }
+
+       if ((mc_header->processor_rev_id[0]) != (equiv_cpu_id & 0xff)) {
+               printk(KERN_ERR
+                       "microcode: CPU%d patch does not match "
+                       "(patch is %x, cpu extended is %x) \n",
+                       cpu, mc_header->processor_rev_id[0],
+                       (equiv_cpu_id & 0xff));
+               return 0;
+       }
+
+       if ((mc_header->processor_rev_id[1]) != ((equiv_cpu_id >> 16) & 0xff)) {
+               printk(KERN_ERR "microcode: CPU%d patch does not match "
+                       "(patch is %x, cpu base id is %x) \n",
+                       cpu, mc_header->processor_rev_id[1],
+                       ((equiv_cpu_id >> 16) & 0xff));
+
+               return 0;
+       }
+
+       /* ucode may be northbridge specific */
+       if (mc_header->nb_dev_id) {
+               nb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                           (mc_header->nb_dev_id & 0xff),
+                                           NULL);
+               if ((!nb_pci_dev) ||
+                   (mc_header->nb_rev_id != nb_pci_dev->revision)) {
+                       printk(KERN_ERR "microcode: CPU%d NB mismatch \n", cpu);
+                       pci_dev_put(nb_pci_dev);
+                       return 0;
+               }
+               pci_dev_put(nb_pci_dev);
+       }
+
+       /* ucode may be southbridge specific */
+       if (mc_header->sb_dev_id) {
+               sb_pci_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+                                           (mc_header->sb_dev_id & 0xff),
+                                           NULL);
+               if ((!sb_pci_dev) ||
+                   (mc_header->sb_rev_id != sb_pci_dev->revision)) {
+                       printk(KERN_ERR "microcode: CPU%d SB mismatch \n", cpu);
+                       pci_dev_put(sb_pci_dev);
+                       return 0;
+               }
+               pci_dev_put(sb_pci_dev);
+       }
+
+       if (mc_header->patch_id <= rev)
+               return 0;
+
+       return 1;
+}
+
+static void apply_microcode_amd(int cpu)
+{
+       unsigned long flags;
+       unsigned int eax, edx;
+       unsigned int rev;
+       int cpu_num = raw_smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
+       struct microcode_amd *mc_amd = uci->mc;
+       unsigned long addr;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu_num != cpu);
+
+       if (mc_amd == NULL)
+               return;
+
+       spin_lock_irqsave(&microcode_update_lock, flags);
+
+       addr = (unsigned long)&mc_amd->hdr.data_code;
+       edx = (unsigned int)(((unsigned long)upper_32_bits(addr)));
+       eax = (unsigned int)(((unsigned long)lower_32_bits(addr)));
+
+       asm volatile("movl %0, %%ecx; wrmsr" :
+                    : "i" (0xc0010020), "a" (eax), "d" (edx) : "ecx");
+
+       /* get patch id after patching */
+       asm volatile("movl %1, %%ecx; rdmsr"
+                    : "=a" (rev)
+                    : "i" (0x0000008B) : "ecx");
+
+       spin_unlock_irqrestore(&microcode_update_lock, flags);
+
+       /* check current patch id and patch's id for match */
+       if (rev != mc_amd->hdr.patch_id) {
+               printk(KERN_ERR "microcode: CPU%d update from revision "
+                      "0x%x to 0x%x failed\n", cpu_num,
+                      mc_amd->hdr.patch_id, rev);
+               return;
+       }
+
+       printk(KERN_INFO "microcode: CPU%d updated from revision "
+              "0x%x to 0x%x \n",
+              cpu_num, uci->cpu_sig.rev, mc_amd->hdr.patch_id);
+
+       uci->cpu_sig.rev = rev;
+}
+
+static void * get_next_ucode(u8 *buf, unsigned int size,
+                       int (*get_ucode_data)(void *, const void *, size_t),
+                       unsigned int *mc_size)
+{
+       unsigned int total_size;
+#define UCODE_CONTAINER_SECTION_HDR    8
+       u8 section_hdr[UCODE_CONTAINER_SECTION_HDR];
+       void *mc;
+
+       if (get_ucode_data(section_hdr, buf, UCODE_CONTAINER_SECTION_HDR))
+               return NULL;
+
+       if (section_hdr[0] != UCODE_UCODE_TYPE) {
+               printk(KERN_ERR "microcode: error! "
+                      "Wrong microcode payload type field\n");
+               return NULL;
+       }
+
+       total_size = (unsigned long) (section_hdr[4] + (section_hdr[5] << 8));
+
+       printk(KERN_INFO "microcode: size %u, total_size %u\n",
+               size, total_size);
+
+       if (total_size > size || total_size > UCODE_MAX_SIZE) {
+               printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+               return NULL;
+       }
+
+       mc = vmalloc(UCODE_MAX_SIZE);
+       if (mc) {
+               memset(mc, 0, UCODE_MAX_SIZE);
+               if (get_ucode_data(mc, buf + UCODE_CONTAINER_SECTION_HDR, total_size)) {
+                       vfree(mc);
+                       mc = NULL;
+               } else
+                       *mc_size = total_size + UCODE_CONTAINER_SECTION_HDR;
+       }
+#undef UCODE_CONTAINER_SECTION_HDR
+       return mc;
+}
+
+
+static int install_equiv_cpu_table(u8 *buf,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+#define UCODE_CONTAINER_HEADER_SIZE    12
+       u8 *container_hdr[UCODE_CONTAINER_HEADER_SIZE];
+       unsigned int *buf_pos = (unsigned int *)container_hdr;
+       unsigned long size;
+
+       if (get_ucode_data(&container_hdr, buf, UCODE_CONTAINER_HEADER_SIZE))
+               return 0;
+
+       size = buf_pos[2];
+
+       if (buf_pos[1] != UCODE_EQUIV_CPU_TABLE_TYPE || !size) {
+               printk(KERN_ERR "microcode: error! "
+                      "Wrong microcode equivalnet cpu table\n");
+               return 0;
+       }
+
+       equiv_cpu_table = (struct equiv_cpu_entry *) vmalloc(size);
+       if (!equiv_cpu_table) {
+               printk(KERN_ERR "microcode: error, can't allocate memory for equiv CPU table\n");
+               return 0;
+       }
+
+       buf += UCODE_CONTAINER_HEADER_SIZE;
+       if (get_ucode_data(equiv_cpu_table, buf, size)) {
+               vfree(equiv_cpu_table);
+               return 0;
+       }
+
+       return size + UCODE_CONTAINER_HEADER_SIZE; /* add header length */
+#undef UCODE_CONTAINER_HEADER_SIZE
+}
+
+static void free_equiv_cpu_table(void)
+{
+       if (equiv_cpu_table) {
+               vfree(equiv_cpu_table);
+               equiv_cpu_table = NULL;
+       }
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+       int new_rev = uci->cpu_sig.rev;
+       unsigned int leftover;
+       unsigned long offset;
+
+       offset = install_equiv_cpu_table(ucode_ptr, get_ucode_data);
+       if (!offset) {
+               printk(KERN_ERR "microcode: installing equivalent cpu table failed\n");
+               return -EINVAL;
+       }
+
+       ucode_ptr += offset;
+       leftover = size - offset;
+
+       while (leftover) {
+               unsigned int uninitialized_var(mc_size);
+               struct microcode_header_amd *mc_header;
+
+               mc = get_next_ucode(ucode_ptr, leftover, get_ucode_data, &mc_size);
+               if (!mc)
+                       break;
+
+               mc_header = (struct microcode_header_amd *)mc;
+               if (get_matching_microcode(cpu, mc, new_rev)) {
+                       if (new_mc)
+                               vfree(new_mc);
+                       new_rev = mc_header->patch_id;
+                       new_mc  = mc;
+               } else 
+                       vfree(mc);
+
+               ucode_ptr += mc_size;
+               leftover  -= mc_size;
+       }
+
+       if (new_mc) {
+               if (!leftover) {
+                       if (uci->mc)
+                               vfree(uci->mc);
+                       uci->mc = new_mc;
+                       pr_debug("microcode: CPU%d found a matching microcode update with"
+                               " version 0x%x (current=0x%x)\n",
+                               cpu, new_rev, uci->cpu_sig.rev);
+               } else
+                       vfree(new_mc);
+       }
+
+       free_equiv_cpu_table();
+
+       return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+       memcpy(to, from, n);
+       return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+       const char *fw_name = "amd-ucode/microcode_amd.bin";
+       const struct firmware *firmware;
+       int ret;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+
+       ret = request_firmware(&firmware, fw_name, device);
+       if (ret) {
+               printk(KERN_ERR "microcode: ucode data file %s load failed\n", fw_name);
+               return ret;
+       }
+
+       ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+                       &get_ucode_fw);
+
+       release_firmware(firmware);
+
+       return ret;
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+       printk(KERN_WARNING "microcode: AMD microcode update via /dev/cpu/microcode"
+                       "is not supported\n");
+       return -1;
+}
+
+static void microcode_fini_cpu_amd(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       vfree(uci->mc);
+       uci->mc = NULL;
+}
+
+static struct microcode_ops microcode_amd_ops = {
+       .request_microcode_user           = request_microcode_user,
+       .request_microcode_fw             = request_microcode_fw,
+       .collect_cpu_info                 = collect_cpu_info_amd,
+       .apply_microcode                  = apply_microcode_amd,
+       .microcode_fini_cpu               = microcode_fini_cpu_amd,
+};
+
+struct microcode_ops * __init init_amd_microcode(void)
+{
+       return &microcode_amd_ops;
+}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
new file mode 100644 (file)
index 0000000..936d8d5
--- /dev/null
@@ -0,0 +1,508 @@
+/*
+ *     Intel CPU Microcode Update Driver for Linux
+ *
+ *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *                   2006      Shaohua Li <shaohua.li@intel.com>
+ *
+ *     This driver allows to upgrade microcode on Intel processors
+ *     belonging to IA-32 family - PentiumPro, Pentium II,
+ *     Pentium III, Xeon, Pentium 4, etc.
+ *
+ *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *     Software Developer's Manual
+ *     Order Number 253668 or free download from:
+ *
+ *     http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *     For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Initial release.
+ *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added read() support + cleanups.
+ *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added 'device trimming' support. open(O_WRONLY) zeroes
+ *             and frees the saved copy of applied microcode.
+ *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Added misc device support (now uses both devfs and misc).
+ *             Added MICROCODE_IOCFREE ioctl to clear memory.
+ *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Messages for error cases (non Intel & no suitable microcode).
+ *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->release(). Removed exclusive open and status bitmap.
+ *             Added microcode_rwsem to serialize read()/write()/ioctl().
+ *             Removed global kernel lock usage.
+ *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Write 0 to 0x8B msr and then cpuid before reading revision,
+ *             so that it works even if there were no update done by the
+ *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *             to be 0 on my machine which is why it worked even when I
+ *             disabled update by the BIOS)
+ *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *                          Tigran Aivazian <tigran@veritas.com>
+ *             Intel Pentium 4 processor support and bugfixes.
+ *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *             Bugfix for HT (Hyper-Threading) enabled processors
+ *             whereby processor resources are shared by all logical processors
+ *             in a single CPU package.
+ *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *             Tigran Aivazian <tigran@veritas.com>,
+ *             Serialize updates as required on HT processors due to
+ *             speculative nature of implementation.
+ *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *             Fix the panic when writing zero-length microcode chunk.
+ *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *             Jun Nakajima <jun.nakajima@intel.com>
+ *             Support for the microcode updates in the new format.
+ *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *             because we no longer hold a copy of applied microcode
+ *             in kernel memory.
+ *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *             Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *             Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+#define MICROCODE_VERSION      "2.00"
+
+struct microcode_ops *microcode_ops;
+
+/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
+static DEFINE_MUTEX(microcode_mutex);
+
+struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
+EXPORT_SYMBOL_GPL(ucode_cpu_info);
+
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static int do_microcode_update(const void __user *buf, size_t size)
+{
+       cpumask_t old;
+       int error = 0;
+       int cpu;
+
+       old = current->cpus_allowed;
+
+       for_each_online_cpu(cpu) {
+               struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+               if (!uci->valid)
+                       continue;
+
+               set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+               error = microcode_ops->request_microcode_user(cpu, buf, size);
+               if (error < 0)
+                       goto out;
+               if (!error)
+                       microcode_ops->apply_microcode(cpu);
+       }
+out:
+       set_cpus_allowed_ptr(current, &old);
+       return error;
+}
+
+static int microcode_open(struct inode *unused1, struct file *unused2)
+{
+       cycle_kernel_lock();
+       return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
+static ssize_t microcode_write(struct file *file, const char __user *buf,
+                              size_t len, loff_t *ppos)
+{
+       ssize_t ret;
+
+       if ((len >> PAGE_SHIFT) > num_physpages) {
+               printk(KERN_ERR "microcode: too much data (max %ld pages)\n",
+                      num_physpages);
+               return -EINVAL;
+       }
+
+       get_online_cpus();
+       mutex_lock(&microcode_mutex);
+
+       ret = do_microcode_update(buf, len);
+       if (!ret)
+               ret = (ssize_t)len;
+
+       mutex_unlock(&microcode_mutex);
+       put_online_cpus();
+
+       return ret;
+}
+
+static const struct file_operations microcode_fops = {
+       .owner          = THIS_MODULE,
+       .write          = microcode_write,
+       .open           = microcode_open,
+};
+
+static struct miscdevice microcode_dev = {
+       .minor          = MICROCODE_MINOR,
+       .name           = "microcode",
+       .fops           = &microcode_fops,
+};
+
+static int __init microcode_dev_init(void)
+{
+       int error;
+
+       error = misc_register(&microcode_dev);
+       if (error) {
+               printk(KERN_ERR
+                       "microcode: can't misc_register on minor=%d\n",
+                       MICROCODE_MINOR);
+               return error;
+       }
+
+       return 0;
+}
+
+static void microcode_dev_exit(void)
+{
+       misc_deregister(&microcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while (0)
+#endif
+
+/* fake device for request_firmware */
+struct platform_device *microcode_pdev;
+
+static ssize_t reload_store(struct sys_device *dev,
+                           struct sysdev_attribute *attr,
+                           const char *buf, size_t sz)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+       char *end;
+       unsigned long val = simple_strtoul(buf, &end, 0);
+       int err = 0;
+       int cpu = dev->id;
+
+       if (end == buf)
+               return -EINVAL;
+       if (val == 1) {
+               cpumask_t old = current->cpus_allowed;
+
+               get_online_cpus();
+               if (cpu_online(cpu)) {
+                       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+                       mutex_lock(&microcode_mutex);
+                       if (uci->valid) {
+                               err = microcode_ops->request_microcode_fw(cpu,
+                                               &microcode_pdev->dev);
+                               if (!err)
+                                       microcode_ops->apply_microcode(cpu);
+                       }
+                       mutex_unlock(&microcode_mutex);
+                       set_cpus_allowed_ptr(current, &old);
+               }
+               put_online_cpus();
+       }
+       if (err)
+               return err;
+       return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev,
+                       struct sysdev_attribute *attr, char *buf)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+       return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev,
+                       struct sysdev_attribute *attr, char *buf)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+       return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+       &attr_reload.attr,
+       &attr_version.attr,
+       &attr_processor_flags.attr,
+       NULL
+};
+
+static struct attribute_group mc_attr_group = {
+       .attrs = mc_default_attrs,
+       .name = "microcode",
+};
+
+static void microcode_fini_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       mutex_lock(&microcode_mutex);
+       microcode_ops->microcode_fini_cpu(cpu);
+       uci->valid = 0;
+       mutex_unlock(&microcode_mutex);
+}
+
+static void collect_cpu_info(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       memset(uci, 0, sizeof(*uci));
+       if (!microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig))
+               uci->valid = 1;
+}
+
+static int microcode_resume_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct cpu_signature nsig;
+
+       pr_debug("microcode: CPU%d resumed\n", cpu);
+
+       if (!uci->mc)
+               return 1;
+
+       /*
+        * Let's verify that the 'cached' ucode does belong
+        * to this cpu (a bit of paranoia):
+        */
+       if (microcode_ops->collect_cpu_info(cpu, &nsig)) {
+               microcode_fini_cpu(cpu);
+               return -1;
+       }
+
+       if (memcmp(&nsig, &uci->cpu_sig, sizeof(nsig))) {
+               microcode_fini_cpu(cpu);
+               /* Should we look for a new ucode here? */
+               return 1;
+       }
+
+       return 0;
+}
+
+void microcode_update_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       int err = 0;
+
+       /*
+        * Check if the system resume is in progress (uci->valid != NULL),
+        * otherwise just request a firmware:
+        */
+       if (uci->valid) {
+               err = microcode_resume_cpu(cpu);
+       } else {        
+               collect_cpu_info(cpu);
+               if (uci->valid && system_state == SYSTEM_RUNNING)
+                       err = microcode_ops->request_microcode_fw(cpu,
+                                       &microcode_pdev->dev);
+       }
+       if (!err)
+               microcode_ops->apply_microcode(cpu);
+}
+
+static void microcode_init_cpu(int cpu)
+{
+       cpumask_t old = current->cpus_allowed;
+
+       set_cpus_allowed_ptr(current, &cpumask_of_cpu(cpu));
+       /* We should bind the task to the CPU */
+       BUG_ON(raw_smp_processor_id() != cpu);
+
+       mutex_lock(&microcode_mutex);
+       microcode_update_cpu(cpu);
+       mutex_unlock(&microcode_mutex);
+
+       set_cpus_allowed_ptr(current, &old);
+}
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+       int err, cpu = sys_dev->id;
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       pr_debug("microcode: CPU%d added\n", cpu);
+       memset(uci, 0, sizeof(*uci));
+
+       err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+       if (err)
+               return err;
+
+       microcode_init_cpu(cpu);
+       return 0;
+}
+
+static int mc_sysdev_remove(struct sys_device *sys_dev)
+{
+       int cpu = sys_dev->id;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       pr_debug("microcode: CPU%d removed\n", cpu);
+       microcode_fini_cpu(cpu);
+       sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+       return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+       int cpu = dev->id;
+
+       if (!cpu_online(cpu))
+               return 0;
+
+       /* only CPU 0 will apply ucode here */
+       microcode_update_cpu(0);
+       return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+       .add = mc_sysdev_add,
+       .remove = mc_sysdev_remove,
+       .resume = mc_sysdev_resume,
+};
+
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+       unsigned int cpu = (unsigned long)hcpu;
+       struct sys_device *sys_dev;
+
+       sys_dev = get_cpu_sysdev(cpu);
+       switch (action) {
+       case CPU_ONLINE:
+       case CPU_ONLINE_FROZEN:
+               microcode_init_cpu(cpu);
+       case CPU_DOWN_FAILED:
+       case CPU_DOWN_FAILED_FROZEN:
+               pr_debug("microcode: CPU%d added\n", cpu);
+               if (sysfs_create_group(&sys_dev->kobj, &mc_attr_group))
+                       printk(KERN_ERR "microcode: Failed to create the sysfs "
+                               "group for CPU%d\n", cpu);
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               /* Suspend is in progress, only remove the interface */
+               sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+               pr_debug("microcode: CPU%d removed\n", cpu);
+               break;
+       case CPU_DEAD:
+       case CPU_UP_CANCELED_FROZEN:
+               /* The CPU refused to come up during a system resume */
+               microcode_fini_cpu(cpu);
+               break;
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __refdata mc_cpu_notifier = {
+       .notifier_call = mc_cpu_callback,
+};
+
+static int __init microcode_init(void)
+{
+       struct cpuinfo_x86 *c = &cpu_data(0);
+       int error;
+
+       if (c->x86_vendor == X86_VENDOR_INTEL)
+               microcode_ops = init_intel_microcode();
+       else if (c->x86_vendor == X86_VENDOR_AMD)
+               microcode_ops = init_amd_microcode();
+
+       if (!microcode_ops) {
+               printk(KERN_ERR "microcode: no support for this CPU vendor\n");
+               return -ENODEV;
+       }
+
+       error = microcode_dev_init();
+       if (error)
+               return error;
+       microcode_pdev = platform_device_register_simple("microcode", -1,
+                                                        NULL, 0);
+       if (IS_ERR(microcode_pdev)) {
+               microcode_dev_exit();
+               return PTR_ERR(microcode_pdev);
+       }
+
+       get_online_cpus();
+       error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+       put_online_cpus();
+       if (error) {
+               microcode_dev_exit();
+               platform_device_unregister(microcode_pdev);
+               return error;
+       }
+
+       register_hotcpu_notifier(&mc_cpu_notifier);
+
+       printk(KERN_INFO
+              "Microcode Update Driver: v" MICROCODE_VERSION
+              " <tigran@aivazian.fsnet.co.uk>"
+              " <peter.oruba@amd.com>\n");
+
+       return 0;
+}
+
+static void __exit microcode_exit(void)
+{
+       microcode_dev_exit();
+
+       unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+       get_online_cpus();
+       sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+       put_online_cpus();
+
+       platform_device_unregister(microcode_pdev);
+
+       microcode_ops = NULL;
+
+       printk(KERN_INFO
+              "Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
+}
+
+module_init(microcode_init);
+module_exit(microcode_exit);
diff --git a/arch/x86/kernel/microcode_intel.c b/arch/x86/kernel/microcode_intel.c
new file mode 100644 (file)
index 0000000..622dc4a
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ *     Intel CPU Microcode Update Driver for Linux
+ *
+ *     Copyright (C) 2000-2006 Tigran Aivazian <tigran@aivazian.fsnet.co.uk>
+ *                   2006      Shaohua Li <shaohua.li@intel.com>
+ *
+ *     This driver allows to upgrade microcode on Intel processors
+ *     belonging to IA-32 family - PentiumPro, Pentium II,
+ *     Pentium III, Xeon, Pentium 4, etc.
+ *
+ *     Reference: Section 8.11 of Volume 3a, IA-32 Intel? Architecture
+ *     Software Developer's Manual
+ *     Order Number 253668 or free download from:
+ *
+ *     http://developer.intel.com/design/pentium4/manuals/253668.htm
+ *
+ *     For more information, go to http://www.urbanmyth.org/microcode
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     1.0     16 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Initial release.
+ *     1.01    18 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added read() support + cleanups.
+ *     1.02    21 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Added 'device trimming' support. open(O_WRONLY) zeroes
+ *             and frees the saved copy of applied microcode.
+ *     1.03    29 Feb 2000, Tigran Aivazian <tigran@sco.com>
+ *             Made to use devfs (/dev/cpu/microcode) + cleanups.
+ *     1.04    06 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Added misc device support (now uses both devfs and misc).
+ *             Added MICROCODE_IOCFREE ioctl to clear memory.
+ *     1.05    09 Jun 2000, Simon Trimmer <simon@veritas.com>
+ *             Messages for error cases (non Intel & no suitable microcode).
+ *     1.06    03 Aug 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->release(). Removed exclusive open and status bitmap.
+ *             Added microcode_rwsem to serialize read()/write()/ioctl().
+ *             Removed global kernel lock usage.
+ *     1.07    07 Sep 2000, Tigran Aivazian <tigran@veritas.com>
+ *             Write 0 to 0x8B msr and then cpuid before reading revision,
+ *             so that it works even if there were no update done by the
+ *             BIOS. Otherwise, reading from 0x8B gives junk (which happened
+ *             to be 0 on my machine which is why it worked even when I
+ *             disabled update by the BIOS)
+ *             Thanks to Eric W. Biederman <ebiederman@lnxi.com> for the fix.
+ *     1.08    11 Dec 2000, Richard Schaal <richard.schaal@intel.com> and
+ *                          Tigran Aivazian <tigran@veritas.com>
+ *             Intel Pentium 4 processor support and bugfixes.
+ *     1.09    30 Oct 2001, Tigran Aivazian <tigran@veritas.com>
+ *             Bugfix for HT (Hyper-Threading) enabled processors
+ *             whereby processor resources are shared by all logical processors
+ *             in a single CPU package.
+ *     1.10    28 Feb 2002 Asit K Mallick <asit.k.mallick@intel.com> and
+ *             Tigran Aivazian <tigran@veritas.com>,
+ *             Serialize updates as required on HT processors due to
+ *             speculative nature of implementation.
+ *     1.11    22 Mar 2002 Tigran Aivazian <tigran@veritas.com>
+ *             Fix the panic when writing zero-length microcode chunk.
+ *     1.12    29 Sep 2003 Nitin Kamble <nitin.a.kamble@intel.com>,
+ *             Jun Nakajima <jun.nakajima@intel.com>
+ *             Support for the microcode updates in the new format.
+ *     1.13    10 Oct 2003 Tigran Aivazian <tigran@veritas.com>
+ *             Removed ->read() method and obsoleted MICROCODE_IOCFREE ioctl
+ *             because we no longer hold a copy of applied microcode
+ *             in kernel memory.
+ *     1.14    25 Jun 2004 Tigran Aivazian <tigran@veritas.com>
+ *             Fix sigmatch() macro to handle old CPUs with pf == 0.
+ *             Thanks to Stuart Swales for pointing out this bug.
+ */
+#include <linux/capability.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <asm/msr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/microcode.h>
+
+MODULE_DESCRIPTION("Microcode Update Driver");
+MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
+MODULE_LICENSE("GPL");
+
+struct microcode_header_intel {
+       unsigned int            hdrver;
+       unsigned int            rev;
+       unsigned int            date;
+       unsigned int            sig;
+       unsigned int            cksum;
+       unsigned int            ldrver;
+       unsigned int            pf;
+       unsigned int            datasize;
+       unsigned int            totalsize;
+       unsigned int            reserved[3];
+};
+
+struct microcode_intel {
+       struct microcode_header_intel hdr;
+       unsigned int            bits[0];
+};
+
+/* microcode format is extended from prescott processors */
+struct extended_signature {
+       unsigned int            sig;
+       unsigned int            pf;
+       unsigned int            cksum;
+};
+
+struct extended_sigtable {
+       unsigned int            count;
+       unsigned int            cksum;
+       unsigned int            reserved[3];
+       struct extended_signature sigs[0];
+};
+
+#define DEFAULT_UCODE_DATASIZE         (2000)
+#define MC_HEADER_SIZE         (sizeof(struct microcode_header_intel))
+#define DEFAULT_UCODE_TOTALSIZE (DEFAULT_UCODE_DATASIZE + MC_HEADER_SIZE)
+#define EXT_HEADER_SIZE                (sizeof(struct extended_sigtable))
+#define EXT_SIGNATURE_SIZE     (sizeof(struct extended_signature))
+#define DWSIZE                 (sizeof(u32))
+#define get_totalsize(mc) \
+       (((struct microcode_intel *)mc)->hdr.totalsize ? \
+        ((struct microcode_intel *)mc)->hdr.totalsize : \
+        DEFAULT_UCODE_TOTALSIZE)
+
+#define get_datasize(mc) \
+       (((struct microcode_intel *)mc)->hdr.datasize ? \
+        ((struct microcode_intel *)mc)->hdr.datasize : DEFAULT_UCODE_DATASIZE)
+
+#define sigmatch(s1, s2, p1, p2) \
+       (((s1) == (s2)) && (((p1) & (p2)) || (((p1) == 0) && ((p2) == 0))))
+
+#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+
+/* serialize access to the physical write to MSR 0x79 */
+static DEFINE_SPINLOCK(microcode_update_lock);
+
+static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
+{
+       struct cpuinfo_x86 *c = &cpu_data(cpu_num);
+       unsigned int val[2];
+
+       memset(csig, 0, sizeof(*csig));
+
+       if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+           cpu_has(c, X86_FEATURE_IA64)) {
+               printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+                       "processor\n", cpu_num);
+               return -1;
+       }
+
+       csig->sig = cpuid_eax(0x00000001);
+
+       if ((c->x86_model >= 5) || (c->x86 > 6)) {
+               /* get processor flags from MSR 0x17 */
+               rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+               csig->pf = 1 << ((val[1] >> 18) & 7);
+       }
+
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
+       /* get the current revision from MSR 0x8B */
+       rdmsr(MSR_IA32_UCODE_REV, val[0], csig->rev);
+       pr_debug("microcode: collect_cpu_info : sig=0x%x, pf=0x%x, rev=0x%x\n",
+                       csig->sig, csig->pf, csig->rev);
+
+       return 0;
+}
+
+static inline int update_match_cpu(struct cpu_signature *csig, int sig, int pf)
+{
+       return (!sigmatch(sig, csig->sig, pf, csig->pf)) ? 0 : 1;
+}
+
+static inline int 
+update_match_revision(struct microcode_header_intel *mc_header,        int rev)
+{
+       return (mc_header->rev <= rev) ? 0 : 1;
+}
+
+static int microcode_sanity_check(void *mc)
+{
+       struct microcode_header_intel *mc_header = mc;
+       struct extended_sigtable *ext_header = NULL;
+       struct extended_signature *ext_sig;
+       unsigned long total_size, data_size, ext_table_size;
+       int sum, orig_sum, ext_sigcount = 0, i;
+
+       total_size = get_totalsize(mc_header);
+       data_size = get_datasize(mc_header);
+       if (data_size + MC_HEADER_SIZE > total_size) {
+               printk(KERN_ERR "microcode: error! "
+                       "Bad data size in microcode data file\n");
+               return -EINVAL;
+       }
+
+       if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+               printk(KERN_ERR "microcode: error! "
+                       "Unknown microcode update format\n");
+               return -EINVAL;
+       }
+       ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+       if (ext_table_size) {
+               if ((ext_table_size < EXT_HEADER_SIZE)
+                || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+                       printk(KERN_ERR "microcode: error! "
+                               "Small exttable size in microcode data file\n");
+                       return -EINVAL;
+               }
+               ext_header = mc + MC_HEADER_SIZE + data_size;
+               if (ext_table_size != exttable_size(ext_header)) {
+                       printk(KERN_ERR "microcode: error! "
+                               "Bad exttable size in microcode data file\n");
+                       return -EFAULT;
+               }
+               ext_sigcount = ext_header->count;
+       }
+
+       /* check extended table checksum */
+       if (ext_table_size) {
+               int ext_table_sum = 0;
+               int *ext_tablep = (int *)ext_header;
+
+               i = ext_table_size / DWSIZE;
+               while (i--)
+                       ext_table_sum += ext_tablep[i];
+               if (ext_table_sum) {
+                       printk(KERN_WARNING "microcode: aborting, "
+                               "bad extended signature table checksum\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* calculate the checksum */
+       orig_sum = 0;
+       i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+       while (i--)
+               orig_sum += ((int *)mc)[i];
+       if (orig_sum) {
+               printk(KERN_ERR "microcode: aborting, bad checksum\n");
+               return -EINVAL;
+       }
+       if (!ext_table_size)
+               return 0;
+       /* check extended signature checksum */
+       for (i = 0; i < ext_sigcount; i++) {
+               ext_sig = (void *)ext_header + EXT_HEADER_SIZE +
+                         EXT_SIGNATURE_SIZE * i;
+               sum = orig_sum
+                       - (mc_header->sig + mc_header->pf + mc_header->cksum)
+                       + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+               if (sum) {
+                       printk(KERN_ERR "microcode: aborting, bad checksum\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ */
+static int
+get_matching_microcode(struct cpu_signature *cpu_sig, void *mc, int rev)
+{
+       struct microcode_header_intel *mc_header = mc;
+       struct extended_sigtable *ext_header;
+       unsigned long total_size = get_totalsize(mc_header);
+       int ext_sigcount, i;
+       struct extended_signature *ext_sig;
+
+       if (!update_match_revision(mc_header, rev))
+               return 0;
+
+       if (update_match_cpu(cpu_sig, mc_header->sig, mc_header->pf))
+               return 1;
+
+       /* Look for ext. headers: */
+       if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+               return 0;
+
+       ext_header = mc + get_datasize(mc_header) + MC_HEADER_SIZE;
+       ext_sigcount = ext_header->count;
+       ext_sig = (void *)ext_header + EXT_HEADER_SIZE;
+
+       for (i = 0; i < ext_sigcount; i++) {
+               if (update_match_cpu(cpu_sig, ext_sig->sig, ext_sig->pf))
+                       return 1;
+               ext_sig++;
+       }
+       return 0;
+}
+
+static void apply_microcode(int cpu)
+{
+       unsigned long flags;
+       unsigned int val[2];
+       int cpu_num = raw_smp_processor_id();
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct microcode_intel *mc_intel = uci->mc;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu_num != cpu);
+
+       if (mc_intel == NULL)
+               return;
+
+       /* serialize access to the physical write to MSR 0x79 */
+       spin_lock_irqsave(&microcode_update_lock, flags);
+
+       /* write microcode via MSR 0x79 */
+       wrmsr(MSR_IA32_UCODE_WRITE,
+             (unsigned long) mc_intel->bits,
+             (unsigned long) mc_intel->bits >> 16 >> 16);
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+
+       /* see notes above for revision 1.07.  Apparent chip bug */
+       sync_core();
+
+       /* get the current revision from MSR 0x8B */
+       rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+       spin_unlock_irqrestore(&microcode_update_lock, flags);
+       if (val[1] != mc_intel->hdr.rev) {
+               printk(KERN_ERR "microcode: CPU%d update from revision "
+                       "0x%x to 0x%x failed\n", cpu_num, uci->cpu_sig.rev, val[1]);
+               return;
+       }
+       printk(KERN_INFO "microcode: CPU%d updated from revision "
+              "0x%x to 0x%x, date = %04x-%02x-%02x \n",
+               cpu_num, uci->cpu_sig.rev, val[1],
+               mc_intel->hdr.date & 0xffff,
+               mc_intel->hdr.date >> 24,
+               (mc_intel->hdr.date >> 16) & 0xff);
+       uci->cpu_sig.rev = val[1];
+}
+
+static int generic_load_microcode(int cpu, void *data, size_t size,
+               int (*get_ucode_data)(void *, const void *, size_t))
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       u8 *ucode_ptr = data, *new_mc = NULL, *mc;
+       int new_rev = uci->cpu_sig.rev;
+       unsigned int leftover = size;
+
+       while (leftover) {
+               struct microcode_header_intel mc_header;
+               unsigned int mc_size;
+
+               if (get_ucode_data(&mc_header, ucode_ptr, sizeof(mc_header)))
+                       break;
+
+               mc_size = get_totalsize(&mc_header);
+               if (!mc_size || mc_size > leftover) {
+                       printk(KERN_ERR "microcode: error!"
+                                       "Bad data in microcode data file\n");
+                       break;
+               }
+
+               mc = vmalloc(mc_size);
+               if (!mc)
+                       break;
+
+               if (get_ucode_data(mc, ucode_ptr, mc_size) ||
+                   microcode_sanity_check(mc) < 0) {
+                       vfree(mc);
+                       break;
+               }
+
+               if (get_matching_microcode(&uci->cpu_sig, mc, new_rev)) {
+                       if (new_mc)
+                               vfree(new_mc);
+                       new_rev = mc_header.rev;
+                       new_mc  = mc;
+               } else
+                       vfree(mc);
+
+               ucode_ptr += mc_size;
+               leftover  -= mc_size;
+       }
+
+       if (new_mc) {
+               if (!leftover) {
+                       if (uci->mc)
+                               vfree(uci->mc);
+                       uci->mc = (struct microcode_intel *)new_mc;
+                       pr_debug("microcode: CPU%d found a matching microcode update with"
+                                " version 0x%x (current=0x%x)\n",
+                               cpu, new_rev, uci->cpu_sig.rev);
+               } else
+                       vfree(new_mc);
+       }
+
+       return (int)leftover;
+}
+
+static int get_ucode_fw(void *to, const void *from, size_t n)
+{
+       memcpy(to, from, n);
+       return 0;
+}
+
+static int request_microcode_fw(int cpu, struct device *device)
+{
+       char name[30];
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
+       const struct firmware *firmware;
+       int ret;
+
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+       sprintf(name, "intel-ucode/%02x-%02x-%02x",
+               c->x86, c->x86_model, c->x86_mask);
+       ret = request_firmware(&firmware, name, device);
+       if (ret) {
+               pr_debug("microcode: data file %s load failed\n", name);
+               return ret;
+       }
+
+       ret = generic_load_microcode(cpu, (void*)firmware->data, firmware->size,
+                       &get_ucode_fw);
+
+       release_firmware(firmware);
+
+       return ret;
+}
+
+static int get_ucode_user(void *to, const void *from, size_t n)
+{
+       return copy_from_user(to, from, n);
+}
+
+static int request_microcode_user(int cpu, const void __user *buf, size_t size)
+{
+       /* We should bind the task to the CPU */
+       BUG_ON(cpu != raw_smp_processor_id());
+
+       return generic_load_microcode(cpu, (void*)buf, size, &get_ucode_user);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+       vfree(uci->mc);
+       uci->mc = NULL;
+}
+
+struct microcode_ops microcode_intel_ops = {
+       .request_microcode_user           = request_microcode_user,
+       .request_microcode_fw             = request_microcode_fw,
+       .collect_cpu_info                 = collect_cpu_info,
+       .apply_microcode                  = apply_microcode,
+       .microcode_fini_cpu               = microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_intel_microcode(void)
+{
+       return &microcode_intel_ops;
+}
+
diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c
new file mode 100644 (file)
index 0000000..0e9f198
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/spinlock.h>
+#include <linux/module.h>
+
+#include <asm/paravirt.h>
+
+static void default_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+       __raw_spin_lock(lock);
+}
+
+struct pv_lock_ops pv_lock_ops = {
+#ifdef CONFIG_SMP
+       .spin_is_locked = __ticket_spin_is_locked,
+       .spin_is_contended = __ticket_spin_is_contended,
+
+       .spin_lock = __ticket_spin_lock,
+       .spin_lock_flags = default_spin_lock_flags,
+       .spin_trylock = __ticket_spin_trylock,
+       .spin_unlock = __ticket_spin_unlock,
+#endif
+};
+EXPORT_SYMBOL(pv_lock_ops);
+
+void __init paravirt_use_bytelocks(void)
+{
+#ifdef CONFIG_SMP
+       pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
+       pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
+       pv_lock_ops.spin_lock = __byte_spin_lock;
+       pv_lock_ops.spin_trylock = __byte_spin_trylock;
+       pv_lock_ops.spin_unlock = __byte_spin_unlock;
+#endif
+}
index 6b0bb73998ddd3eda7be99bc3068a8d44f7eb987..e4c8fb608873797c381f825cc874c5a4e0506e1b 100644 (file)
@@ -268,17 +268,6 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
        return __get_cpu_var(paravirt_lazy_mode);
 }
 
-void __init paravirt_use_bytelocks(void)
-{
-#ifdef CONFIG_SMP
-       pv_lock_ops.spin_is_locked = __byte_spin_is_locked;
-       pv_lock_ops.spin_is_contended = __byte_spin_is_contended;
-       pv_lock_ops.spin_lock = __byte_spin_lock;
-       pv_lock_ops.spin_trylock = __byte_spin_trylock;
-       pv_lock_ops.spin_unlock = __byte_spin_unlock;
-#endif
-}
-
 struct pv_info pv_info = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
@@ -349,6 +338,10 @@ struct pv_cpu_ops pv_cpu_ops = {
        .write_ldt_entry = native_write_ldt_entry,
        .write_gdt_entry = native_write_gdt_entry,
        .write_idt_entry = native_write_idt_entry,
+
+       .alloc_ldt = paravirt_nop,
+       .free_ldt = paravirt_nop,
+
        .load_sp0 = native_load_sp0,
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
@@ -460,18 +453,6 @@ struct pv_mmu_ops pv_mmu_ops = {
        .set_fixmap = native_set_fixmap,
 };
 
-struct pv_lock_ops pv_lock_ops = {
-#ifdef CONFIG_SMP
-       .spin_is_locked = __ticket_spin_is_locked,
-       .spin_is_contended = __ticket_spin_is_contended,
-
-       .spin_lock = __ticket_spin_lock,
-       .spin_trylock = __ticket_spin_trylock,
-       .spin_unlock = __ticket_spin_unlock,
-#endif
-};
-EXPORT_SYMBOL(pv_lock_ops);
-
 EXPORT_SYMBOL_GPL(pv_time_ops);
 EXPORT_SYMBOL    (pv_cpu_ops);
 EXPORT_SYMBOL    (pv_mmu_ops);
index 205188db96269c459d0d5cf739c6ce5495e082ea..922c14058f975d92cbb51d764d8a84256ad9f3fb 100644 (file)
@@ -76,47 +76,12 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
        return ((unsigned long *)tsk->thread.sp)[3];
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-#include <asm/nmi.h>
-
-static void cpu_exit_clear(void)
-{
-       int cpu = raw_smp_processor_id();
-
-       idle_task_exit();
-
-       cpu_uninit();
-       irq_ctx_exit(cpu);
-
-       cpu_clear(cpu, cpu_callout_map);
-       cpu_clear(cpu, cpu_callin_map);
-
-       numa_remove_cpu(cpu);
-       c1e_remove_cpu(cpu);
-}
-
-/* We don't actually take CPU down, just spin without interrupts. */
-static inline void play_dead(void)
-{
-       /* This must be done before dead CPU ack */
-       cpu_exit_clear();
-       mb();
-       /* Ack it */
-       __get_cpu_var(cpu_state) = CPU_DEAD;
-
-       /*
-        * With physical CPU hotplug, we should halt the cpu
-        */
-       local_irq_disable();
-       /* mask all interrupts, flush any and all caches, and halt */
-       wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
        BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
index 2a8ccb9238b4719036aef70780b282e60f58acdd..ca80394ef5b80ebff3fb5fad35aec9d683a8b32c 100644 (file)
@@ -86,30 +86,12 @@ void exit_idle(void)
        __exit_idle();
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-DECLARE_PER_CPU(int, cpu_state);
-
-#include <linux/nmi.h>
-/* We halt the CPU with physical CPU hotplug */
-static inline void play_dead(void)
-{
-       idle_task_exit();
-       c1e_remove_cpu(raw_smp_processor_id());
-
-       mb();
-       /* Ack it */
-       __get_cpu_var(cpu_state) = CPU_DEAD;
-
-       local_irq_disable();
-       /* mask all interrupts, flush any and all caches, and halt */
-       wbinvd_halt();
-}
-#else
+#ifndef CONFIG_SMP
 static inline void play_dead(void)
 {
        BUG();
 }
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif
 
 /*
  * The idle thread. There's no useful work to be
@@ -754,12 +736,12 @@ unsigned long get_wchan(struct task_struct *p)
        if (!p || p == current || p->state == TASK_RUNNING)
                return 0;
        stack = (unsigned long)task_stack_page(p);
-       if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE)
+       if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE)
                return 0;
        fp = *(u64 *)(p->thread.sp);
        do {
                if (fp < (unsigned long)stack ||
-                   fp > (unsigned long)stack+THREAD_SIZE)
+                   fp >= (unsigned long)stack+THREAD_SIZE)
                        return 0;
                ip = *(u64 *)(fp+8);
                if (!in_sched_functions(ip))
index e375b658efc316e4e14785b7f2a3ad61e763cd82..0a6d8c12e10dc7742c2e33dd29475874cb9f2b50 100644 (file)
@@ -40,7 +40,9 @@ enum x86_regset {
        REGSET_GENERAL,
        REGSET_FP,
        REGSET_XFP,
+       REGSET_IOPERM64 = REGSET_XFP,
        REGSET_TLS,
+       REGSET_IOPERM32,
 };
 
 /*
@@ -555,6 +557,29 @@ static int ptrace_set_debugreg(struct task_struct *child,
        return 0;
 }
 
+/*
+ * These access the current or another (stopped) task's io permission
+ * bitmap for debugging or core dump.
+ */
+static int ioperm_active(struct task_struct *target,
+                        const struct user_regset *regset)
+{
+       return target->thread.io_bitmap_max / regset->size;
+}
+
+static int ioperm_get(struct task_struct *target,
+                     const struct user_regset *regset,
+                     unsigned int pos, unsigned int count,
+                     void *kbuf, void __user *ubuf)
+{
+       if (!target->thread.io_bitmap_ptr)
+               return -ENXIO;
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  target->thread.io_bitmap_ptr,
+                                  0, IO_BITMAP_BYTES);
+}
+
 #ifdef CONFIG_X86_PTRACE_BTS
 /*
  * The configuration for a particular BTS hardware implementation.
@@ -1385,6 +1410,12 @@ static const struct user_regset x86_64_regsets[] = {
                .size = sizeof(long), .align = sizeof(long),
                .active = xfpregs_active, .get = xfpregs_get, .set = xfpregs_set
        },
+       [REGSET_IOPERM64] = {
+               .core_note_type = NT_386_IOPERM,
+               .n = IO_BITMAP_LONGS,
+               .size = sizeof(long), .align = sizeof(long),
+               .active = ioperm_active, .get = ioperm_get
+       },
 };
 
 static const struct user_regset_view user_x86_64_view = {
@@ -1431,6 +1462,12 @@ static const struct user_regset x86_32_regsets[] = {
                .active = regset_tls_active,
                .get = regset_tls_get, .set = regset_tls_set
        },
+       [REGSET_IOPERM32] = {
+               .core_note_type = NT_386_IOPERM,
+               .n = IO_BITMAP_BYTES / sizeof(u32),
+               .size = sizeof(u32), .align = sizeof(u32),
+               .active = ioperm_active, .get = ioperm_get
+       },
 };
 
 static const struct user_regset_view user_x86_32_view = {
@@ -1452,7 +1489,8 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 #endif
 }
 
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+                                        int error_code, int si_code)
 {
        struct siginfo info;
 
@@ -1461,7 +1499,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
 
        memset(&info, 0, sizeof(info));
        info.si_signo = SIGTRAP;
-       info.si_code = TRAP_BRKPT;
+       info.si_code = si_code;
 
        /* User-mode ip? */
        info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
@@ -1548,5 +1586,5 @@ asmregparm void syscall_trace_leave(struct pt_regs *regs)
         */
        if (test_thread_flag(TIF_SINGLESTEP) &&
            tracehook_consider_fatal_signal(current, SIGTRAP, SIG_DFL))
-               send_sigtrap(current, regs, 0);
+               send_sigtrap(current, regs, 0, TRAP_BRKPT);
 }
index 46c98efbbf8df0ea84b518b902f70afb6bfb72f1..21b8e0a59780105c673813c9500207758b1def7a 100644 (file)
@@ -581,6 +581,190 @@ static struct x86_quirks default_x86_quirks __initdata;
 
 struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
 
+/*
+ * Some BIOSes seem to corrupt the low 64k of memory during events
+ * like suspend/resume and unplugging an HDMI cable.  Reserve all
+ * remaining free memory in that area and fill it with a distinct
+ * pattern.
+ */
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+#define MAX_SCAN_AREAS 8
+
+static int __read_mostly memory_corruption_check = -1;
+
+static unsigned __read_mostly corruption_check_size = 64*1024;
+static unsigned __read_mostly corruption_check_period = 60; /* seconds */
+
+static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static int num_scan_areas;
+
+
+static int set_corruption_check(char *arg)
+{
+       char *end;
+
+       memory_corruption_check = simple_strtol(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check", set_corruption_check);
+
+static int set_corruption_check_period(char *arg)
+{
+       char *end;
+
+       corruption_check_period = simple_strtoul(arg, &end, 10);
+
+       return (*end == 0) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_period", set_corruption_check_period);
+
+static int set_corruption_check_size(char *arg)
+{
+       char *end;
+       unsigned size;
+
+       size = memparse(arg, &end);
+
+       if (*end == '\0')
+               corruption_check_size = size;
+
+       return (size == corruption_check_size) ? 0 : -EINVAL;
+}
+early_param("memory_corruption_check_size", set_corruption_check_size);
+
+
+static void __init setup_bios_corruption_check(void)
+{
+       u64 addr = PAGE_SIZE;   /* assume first page is reserved anyway */
+
+       if (memory_corruption_check == -1) {
+               memory_corruption_check =
+#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
+                       1
+#else
+                       0
+#endif
+                       ;
+       }
+
+       if (corruption_check_size == 0)
+               memory_corruption_check = 0;
+
+       if (!memory_corruption_check)
+               return;
+
+       corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
+
+       while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
+               u64 size;
+               addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+
+               if (addr == 0)
+                       break;
+
+               if ((addr + size) > corruption_check_size)
+                       size = corruption_check_size - addr;
+
+               if (size == 0)
+                       break;
+
+               e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+               scan_areas[num_scan_areas].addr = addr;
+               scan_areas[num_scan_areas].size = size;
+               num_scan_areas++;
+
+               /* Assume we've already mapped this early memory */
+               memset(__va(addr), 0, size);
+
+               addr += size;
+       }
+
+       printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
+              num_scan_areas);
+       update_e820();
+}
+
+static struct timer_list periodic_check_timer;
+
+void check_for_bios_corruption(void)
+{
+       int i;
+       int corruption = 0;
+
+       if (!memory_corruption_check)
+               return;
+
+       for(i = 0; i < num_scan_areas; i++) {
+               unsigned long *addr = __va(scan_areas[i].addr);
+               unsigned long size = scan_areas[i].size;
+
+               for(; size; addr++, size -= sizeof(unsigned long)) {
+                       if (!*addr)
+                               continue;
+                       printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
+                              addr, __pa(addr), *addr);
+                       corruption = 1;
+                       *addr = 0;
+               }
+       }
+
+       WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
+}
+
+static void periodic_check_for_corruption(unsigned long data)
+{
+       check_for_bios_corruption();
+       mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
+}
+
+void start_periodic_check_for_corruption(void)
+{
+       if (!memory_corruption_check || corruption_check_period == 0)
+               return;
+
+       printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
+              corruption_check_period);
+
+       init_timer(&periodic_check_timer);
+       periodic_check_timer.function = &periodic_check_for_corruption;
+       periodic_check_for_corruption(0);
+}
+#endif
+
+static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
+{
+       printk(KERN_NOTICE
+               "%s detected: BIOS may corrupt low RAM, working it around.\n",
+               d->ident);
+
+       e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
+       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+
+       return 0;
+}
+
+/* List of systems that have known low memory corruption BIOS problems */
+static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
+#ifdef CONFIG_X86_RESERVE_LOW_64K
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "AMI BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+               },
+       },
+       {
+               .callback = dmi_low_memory_corruption,
+               .ident = "Phoenix BIOS",
+               .matches = {
+                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
+               },
+       },
+#endif
+       {}
+};
+
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -715,6 +899,10 @@ void __init setup_arch(char **cmdline_p)
 
        finish_e820_parsing();
 
+       dmi_scan_machine();
+
+       dmi_check_system(bad_bios_dmi_table);
+
 #ifdef CONFIG_X86_32
        probe_roms();
 #endif
@@ -771,6 +959,10 @@ void __init setup_arch(char **cmdline_p)
        high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
 #endif
 
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+       setup_bios_corruption_check();
+#endif
+
        /* max_pfn_mapped is updated here */
        max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
        max_pfn_mapped = max_low_pfn_mapped;
@@ -799,8 +991,6 @@ void __init setup_arch(char **cmdline_p)
        vsmp_init();
 #endif
 
-       dmi_scan_machine();
-
        io_delay_init();
 
        /*
@@ -903,3 +1093,5 @@ void __init setup_arch(char **cmdline_p)
 #endif
 #endif
 }
+
+
index b21070ea33a485c314ed8538288632fb8fa2a869..d6dd057d0f2210784023ee1c591ed4f660e837e2 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/uaccess.h>
 #include <asm/i387.h>
 #include <asm/vdso.h>
+#include <asm/syscall.h>
 #include <asm/syscalls.h>
 
 #include "sigframe.h"
@@ -112,6 +113,27 @@ asmlinkage int sys_sigaltstack(unsigned long bx)
        return do_sigaltstack(uss, uoss, regs->sp);
 }
 
+#define COPY(x)                        {               \
+       err |= __get_user(regs->x, &sc->x);     \
+}
+
+#define COPY_SEG(seg)          {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp;                        \
+}
+
+#define COPY_SEG_STRICT(seg)   {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp | 3;                    \
+}
+
+#define GET_SEG(seg)           {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               loadsegment(seg, tmp);                  \
+}
 
 /*
  * Do a signal return; undo the signal stack.
@@ -120,28 +142,13 @@ static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
                   unsigned long *pax)
 {
+       void __user *buf;
+       unsigned int tmpflags;
        unsigned int err = 0;
 
        /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)                err |= __get_user(regs->x, &sc->x)
-
-#define COPY_SEG(seg)                                                  \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         regs->seg = tmp; }
-
-#define COPY_SEG_STRICT(seg)                                           \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         regs->seg = tmp|3; }
-
-#define GET_SEG(seg)                                                   \
-       { unsigned short tmp;                                           \
-         err |= __get_user(tmp, &sc->seg);                             \
-         loadsegment(seg, tmp); }
-
        GET_SEG(gs);
        COPY_SEG(fs);
        COPY_SEG(es);
@@ -151,21 +158,12 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
        COPY_SEG_STRICT(cs);
        COPY_SEG_STRICT(ss);
 
-       {
-               unsigned int tmpflags;
-
-               err |= __get_user(tmpflags, &sc->flags);
-               regs->flags = (regs->flags & ~FIX_EFLAGS) |
-                                               (tmpflags & FIX_EFLAGS);
-               regs->orig_ax = -1;             /* disable syscall checks */
-       }
-
-       {
-               void __user *buf;
+       err |= __get_user(tmpflags, &sc->flags);
+       regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+       regs->orig_ax = -1;             /* disable syscall checks */
 
-               err |= __get_user(buf, &sc->fpstate);
-               err |= restore_i387_xstate(buf);
-       }
+       err |= __get_user(buf, &sc->fpstate);
+       err |= restore_i387_xstate(buf);
 
        err |= __get_user(*pax, &sc->ax);
        return err;
@@ -214,9 +212,8 @@ badframe:
        return 0;
 }
 
-asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
-       struct pt_regs *regs = (struct pt_regs *)&__unused;
        struct rt_sigframe __user *frame;
        unsigned long ax;
        sigset_t set;
@@ -242,10 +239,17 @@ asmlinkage int sys_rt_sigreturn(unsigned long __unused)
        return ax;
 
 badframe:
-       force_sig(SIGSEGV, current);
+       signal_fault(regs, frame, "rt_sigreturn");
        return 0;
 }
 
+asmlinkage int sys_rt_sigreturn(unsigned long __unused)
+{
+       struct pt_regs *regs = (struct pt_regs *)&__unused;
+
+       return do_rt_sigreturn(regs);
+}
+
 /*
  * Set up a signal frame.
  */
@@ -337,39 +341,29 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
 }
 
 static int
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
-           struct pt_regs *regs)
+__setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
+             struct pt_regs *regs)
 {
        struct sigframe __user *frame;
        void __user *restorer;
        int err = 0;
-       int usig;
        void __user *fpstate = NULL;
 
        frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       usig = current_thread_info()->exec_domain
-               && current_thread_info()->exec_domain->signal_invmap
-               && sig < 32
-               ? current_thread_info()->exec_domain->signal_invmap[sig]
-               : sig;
+       if (__put_user(sig, &frame->sig))
+               return -EFAULT;
 
-       err = __put_user(usig, &frame->sig);
-       if (err)
-               goto give_sigsegv;
-
-       err = setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
-       if (err)
-               goto give_sigsegv;
+       if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
+               return -EFAULT;
 
        if (_NSIG_WORDS > 1) {
-               err = __copy_to_user(&frame->extramask, &set->sig[1],
-                                     sizeof(frame->extramask));
-               if (err)
-                       goto give_sigsegv;
+               if (__copy_to_user(&frame->extramask, &set->sig[1],
+                                  sizeof(frame->extramask)))
+                       return -EFAULT;
        }
 
        if (current->mm->context.vdso)
@@ -394,7 +388,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        err |= __put_user(0x80cd, (short __user *)(frame->retcode+6));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long)frame;
@@ -409,38 +403,27 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                         sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
        void __user *restorer;
        int err = 0;
-       int usig;
        void __user *fpstate = NULL;
 
        frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
-
-       usig = current_thread_info()->exec_domain
-               && current_thread_info()->exec_domain->signal_invmap
-               && sig < 32
-               ? current_thread_info()->exec_domain->signal_invmap[sig]
-               : sig;
+               return -EFAULT;
 
-       err |= __put_user(usig, &frame->sig);
+       err |= __put_user(sig, &frame->sig);
        err |= __put_user(&frame->info, &frame->pinfo);
        err |= __put_user(&frame->uc, &frame->puc);
        err |= copy_siginfo_to_user(&frame->info, info);
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Create the ucontext.  */
        if (cpu_has_xsave)
@@ -456,7 +439,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                                regs, set->sig[0]);
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up to return from userspace.  */
        restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
@@ -476,12 +459,12 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long)frame;
        regs->ip = (unsigned long)ka->sa.sa_handler;
-       regs->ax = (unsigned long)usig;
+       regs->ax = (unsigned long)sig;
        regs->dx = (unsigned long)&frame->info;
        regs->cx = (unsigned long)&frame->uc;
 
@@ -491,15 +474,48 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler:
  */
+static int signr_convert(int sig)
+{
+       struct thread_info *info = current_thread_info();
+
+       if (info->exec_domain && info->exec_domain->signal_invmap && sig < 32)
+               return info->exec_domain->signal_invmap[sig];
+       return sig;
+}
+
+#define is_ia32        1
+#define ia32_setup_frame       __setup_frame
+#define ia32_setup_rt_frame    __setup_rt_frame
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs *regs)
+{
+       int usig = signr_convert(sig);
+       int ret;
+
+       /* Set up the stack frame */
+       if (is_ia32) {
+               if (ka->sa.sa_flags & SA_SIGINFO)
+                       ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+               else
+                       ret = ia32_setup_frame(usig, ka, set, regs);
+       } else
+               ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+       if (ret) {
+               force_sigsegv(sig, current);
+               return -EFAULT;
+       }
+
+       return ret;
+}
+
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
              sigset_t *oldset, struct pt_regs *regs)
@@ -507,9 +523,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        int ret;
 
        /* Are we from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (syscall_get_nr(current, regs) >= 0) {
                /* If so, check system call restarting.. */
-               switch (regs->ax) {
+               switch (syscall_get_error(current, regs)) {
                case -ERESTART_RESTARTBLOCK:
                case -ERESTARTNOHAND:
                        regs->ax = -EINTR;
@@ -536,15 +552,20 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
            likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
                regs->flags &= ~X86_EFLAGS_TF;
 
-       /* Set up the stack frame */
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               ret = setup_rt_frame(sig, ka, info, oldset, regs);
-       else
-               ret = setup_frame(sig, ka, oldset, regs);
+       ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
        if (ret)
                return ret;
 
+#ifdef CONFIG_X86_64
+       /*
+        * This has nothing to do with segment registers,
+        * despite the name.  This magic affects uaccess.h
+        * macros' behavior.  Reset it to the normal setting.
+        */
+       set_fs(USER_DS);
+#endif
+
        /*
         * Clear the direction flag as per the ABI for function entry.
         */
@@ -571,6 +592,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
        return 0;
 }
 
+#define NR_restart_syscall     __NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -623,9 +645,9 @@ static void do_signal(struct pt_regs *regs)
        }
 
        /* Did we come from a system call? */
-       if ((long)regs->orig_ax >= 0) {
+       if (syscall_get_nr(current, regs) >= 0) {
                /* Restart the system call - no handlers present */
-               switch (regs->ax) {
+               switch (syscall_get_error(current, regs)) {
                case -ERESTARTNOHAND:
                case -ERESTARTSYS:
                case -ERESTARTNOINTR:
@@ -634,7 +656,7 @@ static void do_signal(struct pt_regs *regs)
                        break;
 
                case -ERESTART_RESTARTBLOCK:
-                       regs->ax = __NR_restart_syscall;
+                       regs->ax = NR_restart_syscall;
                        regs->ip -= 2;
                        break;
                }
@@ -657,6 +679,12 @@ static void do_signal(struct pt_regs *regs)
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
+       /* notify userspace of pending MCEs */
+       if (thread_info_flags & _TIF_MCE_NOTIFY)
+               mce_notify_user();
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs);
@@ -666,5 +694,23 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
                tracehook_notify_resume(regs);
        }
 
+#ifdef CONFIG_X86_32
        clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
+}
+
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+{
+       struct task_struct *me = current;
+
+       if (show_unhandled_signals && printk_ratelimit()) {
+               printk(KERN_INFO
+                      "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+                      me->comm, me->pid, where, frame,
+                      regs->ip, regs->sp, regs->orig_ax);
+               print_vma_addr(" in ", regs->ip);
+               printk(KERN_CONT "\n");
+       }
+
+       force_sig(SIGSEGV, me);
 }
index 823a55bf8c3901d4c429073c445bb1ddcc21643d..a5c9627f4db9df635a01373edbaeff215d9c52ae 100644 (file)
@@ -52,6 +52,16 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
        return do_sigaltstack(uss, uoss, regs->sp);
 }
 
+#define COPY(x)                        {               \
+       err |= __get_user(regs->x, &sc->x);     \
+}
+
+#define COPY_SEG_STRICT(seg)   {                       \
+               unsigned short tmp;                     \
+               err |= __get_user(tmp, &sc->seg);       \
+               regs->seg = tmp | 3;                    \
+}
+
 /*
  * Do a signal return; undo the signal stack.
  */
@@ -59,13 +69,13 @@ static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
                   unsigned long *pax)
 {
+       void __user *buf;
+       unsigned int tmpflags;
        unsigned int err = 0;
 
        /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
-#define COPY(x)                (err |= __get_user(regs->x, &sc->x))
-
        COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
        COPY(dx); COPY(cx); COPY(ip);
        COPY(r8);
@@ -80,34 +90,24 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
        /* Kernel saves and restores only the CS segment register on signals,
         * which is the bare minimum needed to allow mixed 32/64-bit code.
         * App's signal handler can save/restore other segments if needed. */
-       {
-               unsigned cs;
-               err |= __get_user(cs, &sc->cs);
-               regs->cs = cs | 3;      /* Force into user mode */
-       }
+       COPY_SEG_STRICT(cs);
 
-       {
-               unsigned int tmpflags;
-               err |= __get_user(tmpflags, &sc->flags);
-               regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
-               regs->orig_ax = -1;             /* disable syscall checks */
-       }
+       err |= __get_user(tmpflags, &sc->flags);
+       regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+       regs->orig_ax = -1;             /* disable syscall checks */
 
-       {
-               struct _fpstate __user *buf;
-               err |= __get_user(buf, &sc->fpstate);
-               err |= restore_i387_xstate(buf);
-       }
+       err |= __get_user(buf, &sc->fpstate);
+       err |= restore_i387_xstate(buf);
 
        err |= __get_user(*pax, &sc->ax);
        return err;
 }
 
-asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+static long do_rt_sigreturn(struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
-       sigset_t set;
        unsigned long ax;
+       sigset_t set;
 
        frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -130,10 +130,15 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
        return ax;
 
 badframe:
-       signal_fault(regs, frame, "sigreturn");
+       signal_fault(regs, frame, "rt_sigreturn");
        return 0;
 }
 
+asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
+{
+       return do_rt_sigreturn(regs);
+}
+
 /*
  * Set up a signal frame.
  */
@@ -195,8 +200,8 @@ get_stack(struct k_sigaction *ka, struct pt_regs *regs, unsigned long size)
        return (void __user *)round_down(sp - size, 64);
 }
 
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                          sigset_t *set, struct pt_regs *regs)
+static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+                           sigset_t *set, struct pt_regs *regs)
 {
        struct rt_sigframe __user *frame;
        void __user *fp = NULL;
@@ -209,17 +214,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                        (unsigned long)fp - sizeof(struct rt_sigframe), 16) - 8;
 
                if (save_i387_xstate(fp) < 0)
-                       err |= -1;
+                       return -EFAULT;
        } else
                frame = get_stack(ka, regs, sizeof(struct rt_sigframe)) - 8;
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
        if (ka->sa.sa_flags & SA_SIGINFO) {
-               err |= copy_siginfo_to_user(&frame->info, info);
-               if (err)
-                       goto give_sigsegv;
+               if (copy_siginfo_to_user(&frame->info, info))
+                       return -EFAULT;
        }
 
        /* Create the ucontext.  */
@@ -247,11 +251,11 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
                err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
        } else {
                /* could use a vstub here */
-               goto give_sigsegv;
+               return -EFAULT;
        }
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* Set up registers for signal handler */
        regs->di = sig;
@@ -271,15 +275,45 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->cs = __USER_CS;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 /*
  * OK, we're invoking a handler
  */
+static int signr_convert(int sig)
+{
+       return sig;
+}
+
+#ifdef CONFIG_IA32_EMULATION
+#define is_ia32        test_thread_flag(TIF_IA32)
+#else
+#define is_ia32        0
+#endif
+
+static int
+setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+              sigset_t *set, struct pt_regs *regs)
+{
+       int usig = signr_convert(sig);
+       int ret;
+
+       /* Set up the stack frame */
+       if (is_ia32) {
+               if (ka->sa.sa_flags & SA_SIGINFO)
+                       ret = ia32_setup_rt_frame(usig, ka, info, set, regs);
+               else
+                       ret = ia32_setup_frame(usig, ka, set, regs);
+       } else
+               ret = __setup_rt_frame(sig, ka, info, set, regs);
+
+       if (ret) {
+               force_sigsegv(sig, current);
+               return -EFAULT;
+       }
+
+       return ret;
+}
 
 static int
 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
@@ -317,51 +351,48 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
            likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
                regs->flags &= ~X86_EFLAGS_TF;
 
-#ifdef CONFIG_IA32_EMULATION
-       if (test_thread_flag(TIF_IA32)) {
-               if (ka->sa.sa_flags & SA_SIGINFO)
-                       ret = ia32_setup_rt_frame(sig, ka, info, oldset, regs);
-               else
-                       ret = ia32_setup_frame(sig, ka, oldset, regs);
-       } else
-#endif
        ret = setup_rt_frame(sig, ka, info, oldset, regs);
 
-       if (ret == 0) {
-               /*
-                * This has nothing to do with segment registers,
-                * despite the name.  This magic affects uaccess.h
-                * macros' behavior.  Reset it to the normal setting.
-                */
-               set_fs(USER_DS);
+       if (ret)
+               return ret;
 
-               /*
-                * Clear the direction flag as per the ABI for function entry.
-                */
-               regs->flags &= ~X86_EFLAGS_DF;
+#ifdef CONFIG_X86_64
+       /*
+        * This has nothing to do with segment registers,
+        * despite the name.  This magic affects uaccess.h
+        * macros' behavior.  Reset it to the normal setting.
+        */
+       set_fs(USER_DS);
+#endif
 
-               /*
-                * Clear TF when entering the signal handler, but
-                * notify any tracer that was single-stepping it.
-                * The tracer may want to single-step inside the
-                * handler too.
-                */
-               regs->flags &= ~X86_EFLAGS_TF;
+       /*
+        * Clear the direction flag as per the ABI for function entry.
+        */
+       regs->flags &= ~X86_EFLAGS_DF;
 
-               spin_lock_irq(&current->sighand->siglock);
-               sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
-               if (!(ka->sa.sa_flags & SA_NODEFER))
-                       sigaddset(&current->blocked, sig);
-               recalc_sigpending();
-               spin_unlock_irq(&current->sighand->siglock);
+       /*
+        * Clear TF when entering the signal handler, but
+        * notify any tracer that was single-stepping it.
+        * The tracer may want to single-step inside the
+        * handler too.
+        */
+       regs->flags &= ~X86_EFLAGS_TF;
 
-               tracehook_signal_handler(sig, info, ka, regs,
-                                        test_thread_flag(TIF_SINGLESTEP));
-       }
+       spin_lock_irq(&current->sighand->siglock);
+       sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+       if (!(ka->sa.sa_flags & SA_NODEFER))
+               sigaddset(&current->blocked, sig);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
 
-       return ret;
+       tracehook_signal_handler(sig, info, ka, regs,
+                                test_thread_flag(TIF_SINGLESTEP));
+
+       return 0;
 }
 
+#define NR_restart_syscall     \
+       test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
 /*
  * Note that 'init' is a special process: it doesn't get signals it doesn't
  * want to handle. Thus you cannot kill init even with a SIGKILL even by
@@ -391,7 +422,8 @@ static void do_signal(struct pt_regs *regs)
 
        signr = get_signal_to_deliver(&info, &ka, regs, NULL);
        if (signr > 0) {
-               /* Re-enable any watchpoints before delivering the
+               /*
+                * Re-enable any watchpoints before delivering the
                 * signal to user space. The processor register will
                 * have been cleared if the watchpoint triggered
                 * inside the kernel.
@@ -399,7 +431,7 @@ static void do_signal(struct pt_regs *regs)
                if (current->thread.debugreg7)
                        set_debugreg(current->thread.debugreg7, 7);
 
-               /* Whee!  Actually deliver the signal.  */
+               /* Whee! Actually deliver the signal.  */
                if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
                        /*
                         * A signal was successfully delivered; the saved
@@ -422,10 +454,9 @@ static void do_signal(struct pt_regs *regs)
                        regs->ax = regs->orig_ax;
                        regs->ip -= 2;
                        break;
+
                case -ERESTART_RESTARTBLOCK:
-                       regs->ax = test_thread_flag(TIF_IA32) ?
-                                       __NR_ia32_restart_syscall :
-                                       __NR_restart_syscall;
+                       regs->ax = NR_restart_syscall;
                        regs->ip -= 2;
                        break;
                }
@@ -441,14 +472,18 @@ static void do_signal(struct pt_regs *regs)
        }
 }
 
-void do_notify_resume(struct pt_regs *regs, void *unused,
-                     __u32 thread_info_flags)
+/*
+ * notification of userspace execution resumption
+ * - triggered by the TIF_WORK_MASK flags
+ */
+void
+do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
-#ifdef CONFIG_X86_MCE
+#if defined(CONFIG_X86_64) && defined(CONFIG_X86_MCE)
        /* notify userspace of pending MCEs */
        if (thread_info_flags & _TIF_MCE_NOTIFY)
                mce_notify_user();
-#endif /* CONFIG_X86_MCE */
+#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
 
        /* deal with pending signal delivery */
        if (thread_info_flags & _TIF_SIGPENDING)
@@ -458,17 +493,23 @@ void do_notify_resume(struct pt_regs *regs, void *unused,
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
        }
+
+#ifdef CONFIG_X86_32
+       clear_thread_flag(TIF_IRET);
+#endif /* CONFIG_X86_32 */
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
 {
        struct task_struct *me = current;
+
        if (show_unhandled_signals && printk_ratelimit()) {
-               printk("%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
-              me->comm, me->pid, where, frame, regs->ip,
-                  regs->sp, regs->orig_ax);
+               printk(KERN_INFO
+                      "%s[%d] bad frame in %s frame:%p ip:%lx sp:%lx orax:%lx",
+                      me->comm, me->pid, where, frame,
+                      regs->ip, regs->sp, regs->orig_ax);
                print_vma_addr(" in ", regs->ip);
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
 
        force_sig(SIGSEGV, me);
index 361b7a4c640c2d9efaee2d95f860bc83d985a2a5..18f9b19f5f8f5d46582b64501d83d11cb4376eb6 100644 (file)
@@ -214,12 +214,16 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
 struct smp_ops smp_ops = {
        .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu,
        .smp_prepare_cpus = native_smp_prepare_cpus,
-       .cpu_up = native_cpu_up,
        .smp_cpus_done = native_smp_cpus_done,
 
        .smp_send_stop = native_smp_send_stop,
        .smp_send_reschedule = native_smp_send_reschedule,
 
+       .cpu_up = native_cpu_up,
+       .cpu_die = native_cpu_die,
+       .cpu_disable = native_cpu_disable,
+       .play_dead = native_play_dead,
+
        .send_call_func_ipi = native_send_call_func_ipi,
        .send_call_func_single_ipi = native_send_call_func_single_ipi,
 };
index 9056f7e272c02a017d331e4d59a6a1bfccd0e074..76b6f50978f7f7219125ffb05b55fa1fd4f273a0 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/desc.h>
 #include <asm/nmi.h>
 #include <asm/irq.h>
+#include <asm/idle.h>
 #include <asm/smp.h>
 #include <asm/trampoline.h>
 #include <asm/cpu.h>
@@ -1344,25 +1345,9 @@ static void __ref remove_cpu_from_maps(int cpu)
        numa_remove_cpu(cpu);
 }
 
-int __cpu_disable(void)
+void cpu_disable_common(void)
 {
        int cpu = smp_processor_id();
-
-       /*
-        * Perhaps use cpufreq to drop frequency, but that could go
-        * into generic code.
-        *
-        * We won't take down the boot processor on i386 due to some
-        * interrupts only being able to be serviced by the BSP.
-        * Especially so if we're not using an IOAPIC   -zwane
-        */
-       if (cpu == 0)
-               return -EBUSY;
-
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               stop_apic_nmi_watchdog(NULL);
-       clear_local_APIC();
-
        /*
         * HACK:
         * Allow any queued timer interrupts to get serviced
@@ -1380,10 +1365,32 @@ int __cpu_disable(void)
        remove_cpu_from_maps(cpu);
        unlock_vector_lock();
        fixup_irqs(cpu_online_map);
+}
+
+int native_cpu_disable(void)
+{
+       int cpu = smp_processor_id();
+
+       /*
+        * Perhaps use cpufreq to drop frequency, but that could go
+        * into generic code.
+        *
+        * We won't take down the boot processor on i386 due to some
+        * interrupts only being able to be serviced by the BSP.
+        * Especially so if we're not using an IOAPIC   -zwane
+        */
+       if (cpu == 0)
+               return -EBUSY;
+
+       if (nmi_watchdog == NMI_LOCAL_APIC)
+               stop_apic_nmi_watchdog(NULL);
+       clear_local_APIC();
+
+       cpu_disable_common();
        return 0;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
        /* We don't do anything here: idle task is faking death itself. */
        unsigned int i;
@@ -1400,15 +1407,45 @@ void __cpu_die(unsigned int cpu)
        }
        printk(KERN_ERR "CPU %u didn't die...\n", cpu);
 }
+
+void play_dead_common(void)
+{
+       idle_task_exit();
+       reset_lazy_tlbstate();
+       irq_ctx_exit(raw_smp_processor_id());
+       c1e_remove_cpu(raw_smp_processor_id());
+
+       mb();
+       /* Ack it */
+       __get_cpu_var(cpu_state) = CPU_DEAD;
+
+       /*
+        * With physical CPU hotplug, we should halt the cpu
+        */
+       local_irq_disable();
+}
+
+void native_play_dead(void)
+{
+       play_dead_common();
+       wbinvd_halt();
+}
+
 #else /* ... !CONFIG_HOTPLUG_CPU */
-int __cpu_disable(void)
+int native_cpu_disable(void)
 {
        return -ENOSYS;
 }
 
-void __cpu_die(unsigned int cpu)
+void native_cpu_die(unsigned int cpu)
 {
        /* We said "no" in __cpu_disable */
        BUG();
 }
+
+void native_play_dead(void)
+{
+       BUG();
+}
+
 #endif
index fec1ecedc9b7486d6504699fa99583e391ceb92e..e00534b3353483dc67bc8282b839c5257a16ca72 100644 (file)
@@ -241,3 +241,11 @@ void flush_tlb_all(void)
        on_each_cpu(do_flush_tlb_all, NULL, 1);
 }
 
+void reset_lazy_tlbstate(void)
+{
+       int cpu = raw_smp_processor_id();
+
+       per_cpu(cpu_tlbstate, cpu).state = 0;
+       per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+
index da5a5964fccb23f1fbdb6ef2d3b82d110973aaed..0429c5de5ea98d9e94a4401798a1de14ceff7394 100644 (file)
@@ -891,6 +891,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
 {
        struct task_struct *tsk = current;
        unsigned int condition;
+       int si_code;
 
        trace_hardirqs_fixup();
 
@@ -935,8 +936,9 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code)
                        goto clear_TF_reenable;
        }
 
+       si_code = get_si_code((unsigned long)condition);
        /* Ok, finally something we can handle */
-       send_sigtrap(tsk, regs, error_code);
+       send_sigtrap(tsk, regs, error_code, si_code);
 
        /*
         * Disable additional traps. They'll be re-enabled when
index 2887a789e38fab315c7ce618a40aa947fe58915c..9c0ac0cab013bc64fb500dcdc56ea07a862cacf7 100644 (file)
@@ -940,7 +940,7 @@ asmlinkage void __kprobes do_debug(struct pt_regs *regs,
        tsk->thread.error_code = error_code;
        info.si_signo = SIGTRAP;
        info.si_errno = 0;
-       info.si_code = TRAP_BRKPT;
+       info.si_code = get_si_code(condition);
        info.si_addr = user_mode(regs) ? (void __user *)regs->ip : NULL;
        force_sig_info(SIGTRAP, &info, tsk);
 
index 201e81a91a95371deeb0dc50269febc0a2714133..46e05447405b43855f46602f493847b75efa252a 100644 (file)
@@ -172,8 +172,8 @@ SECTIONS
   .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
        *(.x86_cpu_dev.init)
   }
-  SECURITY_INIT
   __x86_cpu_dev_end = .;
+  SECURITY_INIT
 
   . = ALIGN(8);
   .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
index 07713d64debe2fffa7cb49e3bcd5bb129572f6a0..9abac8a9d823656b720e81023aed96147b82d6f8 100644 (file)
@@ -95,7 +95,9 @@ int save_i387_xstate(void __user *buf)
                 * Start with clearing the user buffer. This will present a
                 * clean context for the bytes not touched by the fxsave/xsave.
                 */
-               __clear_user(buf, sig_xstate_size);
+               err = __clear_user(buf, sig_xstate_size);
+               if (err)
+                       return err;
 
                if (task_thread_info(tsk)->status & TS_XSAVE)
                        err = xsave_user(buf);
@@ -114,6 +116,8 @@ int save_i387_xstate(void __user *buf)
 
        if (task_thread_info(tsk)->status & TS_XSAVE) {
                struct _fpstate __user *fx = buf;
+               struct _xstate __user *x = buf;
+               u64 xstate_bv;
 
                err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
                                     sizeof(struct _fpx_sw_bytes));
@@ -121,6 +125,31 @@ int save_i387_xstate(void __user *buf)
                err |= __put_user(FP_XSTATE_MAGIC2,
                                  (__u32 __user *) (buf + sig_xstate_size
                                                    - FP_XSTATE_MAGIC2_SIZE));
+
+               /*
+                * Read the xstate_bv which we copied (directly from the cpu or
+                * from the state in task struct) to the user buffers and
+                * set the FP/SSE bits.
+                */
+               err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+               /*
+                * For legacy compatible, we always set FP/SSE bits in the bit
+                * vector while saving the state to the user context. This will
+                * enable us capturing any changes(during sigreturn) to
+                * the FP/SSE bits by the legacy applications which don't touch
+                * xstate_bv in the xsave header.
+                *
+                * xsave aware apps can change the xstate_bv in the xsave
+                * header as well as change any contents in the memory layout.
+                * xrestore as part of sigreturn will capture all the changes.
+                */
+               xstate_bv |= XSTATE_FPSSE;
+
+               err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
+
+               if (err)
+                       return err;
        }
 
        return 1;
@@ -272,7 +301,7 @@ void __cpuinit xsave_init(void)
 /*
  * setup the xstate image representing the init state
  */
-void setup_xstate_init(void)
+static void __init setup_xstate_init(void)
 {
        init_xstate_buf = alloc_bootmem(xstate_size);
        init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
index 8f92cac4e6dbe226b85535b46db44259c066b3ad..a742d753d5b0ae438a65e976354556a8b0c938b1 100644 (file)
@@ -914,15 +914,15 @@ LIST_HEAD(pgd_list);
 
 void vmalloc_sync_all(void)
 {
-#ifdef CONFIG_X86_32
-       unsigned long start = VMALLOC_START & PGDIR_MASK;
        unsigned long address;
 
+#ifdef CONFIG_X86_32
        if (SHARED_KERNEL_PMD)
                return;
 
-       BUILD_BUG_ON(TASK_SIZE & ~PGDIR_MASK);
-       for (address = start; address >= TASK_SIZE; address += PGDIR_SIZE) {
+       for (address = VMALLOC_START & PMD_MASK;
+            address >= TASK_SIZE && address < FIXADDR_TOP;
+            address += PMD_SIZE) {
                unsigned long flags;
                struct page *page;
 
@@ -935,10 +935,8 @@ void vmalloc_sync_all(void)
                spin_unlock_irqrestore(&pgd_lock, flags);
        }
 #else /* CONFIG_X86_64 */
-       unsigned long start = VMALLOC_START & PGDIR_MASK;
-       unsigned long address;
-
-       for (address = start; address <= VMALLOC_END; address += PGDIR_SIZE) {
+       for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
+            address += PGDIR_SIZE) {
                const pgd_t *pgd_ref = pgd_offset_k(address);
                unsigned long flags;
                struct page *page;
index c3789bb193087d99c2946700d14c2474845528c4..bbe044dbe01403b0bdf67dbf4fe7e46e4e00a07e 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/cpumask.h>
 
 #include <asm/asm.h>
+#include <asm/bios_ebda.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -969,6 +970,8 @@ void __init mem_init(void)
        int codesize, reservedpages, datasize, initsize;
        int tmp;
 
+       start_periodic_check_for_corruption();
+
 #ifdef CONFIG_FLATMEM
        BUG_ON(!mem_map);
 #endif
index 83e13f2d53d2a94d95f3e4657eb570ea784c4a72..3e10054c57319c25626bd1f43bf830c11453b255 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/nmi.h>
 
 #include <asm/processor.h>
+#include <asm/bios_ebda.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -881,6 +882,8 @@ void __init mem_init(void)
 {
        long codesize, reservedpages, datasize, initsize;
 
+       start_periodic_check_for_corruption();
+
        pci_iommu_alloc();
 
        /* clear_bss() already clear the empty_zero_page */
index 6ab3196d12b412979cbfba55467968b513670a49..8cbeda15cd29727bee40bc4f15de3a8fd3b573b2 100644 (file)
 
 #ifdef CONFIG_X86_64
 
-unsigned long __phys_addr(unsigned long x)
+static inline int phys_addr_valid(unsigned long addr)
 {
-       if (x >= __START_KERNEL_map)
-               return x - __START_KERNEL_map + phys_base;
-       return x - PAGE_OFFSET;
+       return addr < (1UL << boot_cpu_data.x86_phys_bits);
 }
-EXPORT_SYMBOL(__phys_addr);
 
-static inline int phys_addr_valid(unsigned long addr)
+unsigned long __phys_addr(unsigned long x)
 {
-       return addr < (1UL << boot_cpu_data.x86_phys_bits);
+       if (x >= __START_KERNEL_map) {
+               x -= __START_KERNEL_map;
+               VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
+               x += phys_base;
+       } else {
+               VIRTUAL_BUG_ON(x < PAGE_OFFSET);
+               x -= PAGE_OFFSET;
+               VIRTUAL_BUG_ON(system_state == SYSTEM_BOOTING ? x > MAXMEM :
+                                       !phys_addr_valid(x));
+       }
+       return x;
 }
+EXPORT_SYMBOL(__phys_addr);
 
 #else
 
@@ -44,6 +52,17 @@ static inline int phys_addr_valid(unsigned long addr)
        return 1;
 }
 
+#ifdef CONFIG_DEBUG_VIRTUAL
+unsigned long __phys_addr(unsigned long x)
+{
+       /* VMALLOC_* aren't constants; not available at the boot time */
+       VIRTUAL_BUG_ON(x < PAGE_OFFSET || (system_state != SYSTEM_BOOTING &&
+                                       is_vmalloc_addr((void *)x)));
+       return x - PAGE_OFFSET;
+}
+EXPORT_SYMBOL(__phys_addr);
+#endif
+
 #endif
 
 int page_is_ram(unsigned long pagenr)
@@ -614,7 +633,7 @@ void __init *early_ioremap(unsigned long phys_addr, unsigned long size)
         */
        offset = phys_addr & ~PAGE_MASK;
        phys_addr &= PAGE_MASK;
-       size = PAGE_ALIGN(last_addr) - phys_addr;
+       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
 
        /*
         * Mappings have to fit in the FIX_BTMAP area.
index 3815e425f4702f11a1693ba3a43a49e9dabc05bb..87b9ab166423bca3e46e27e3fa8518de89c30466 100644 (file)
@@ -26,5 +26,13 @@ config XEN_MAX_DOMAIN_MEMORY
 
 config XEN_SAVE_RESTORE
        bool
-       depends on PM
-       default y
\ No newline at end of file
+       depends on XEN && PM
+       default y
+
+config XEN_DEBUG_FS
+       bool "Enable Xen debug and tuning parameters in debugfs"
+       depends on XEN && DEBUG_FS
+       default n
+       help
+         Enable statistics output and various tuning options in debugfs.
+         Enabling this option may incur a significant performance overhead.
index 59c1e539aed28b9d2c8395671be4a459097df7e7..313947940a1af66b309d91e5b8a0d687b9136b98 100644 (file)
@@ -1,4 +1,12 @@
-obj-y          := enlighten.o setup.o multicalls.o mmu.o \
+ifdef CONFIG_FTRACE
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_spinlock.o = -pg
+CFLAGS_REMOVE_time.o = -pg
+CFLAGS_REMOVE_irq.o = -pg
+endif
+
+obj-y          := enlighten.o setup.o multicalls.o mmu.o irq.o \
                        time.o xen-asm_$(BITS).o grant-table.o suspend.o
 
-obj-$(CONFIG_SMP)      += smp.o
+obj-$(CONFIG_SMP)              += smp.o spinlock.o
+obj-$(CONFIG_XEN_DEBUG_FS)     += debugfs.o
\ No newline at end of file
diff --git a/arch/x86/xen/debugfs.c b/arch/x86/xen/debugfs.c
new file mode 100644 (file)
index 0000000..b53225d
--- /dev/null
@@ -0,0 +1,123 @@
+#include <linux/init.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+
+#include "debugfs.h"
+
+static struct dentry *d_xen_debug;
+
+struct dentry * __init xen_init_debugfs(void)
+{
+       if (!d_xen_debug) {
+               d_xen_debug = debugfs_create_dir("xen", NULL);
+
+               if (!d_xen_debug)
+                       pr_warning("Could not create 'xen' debugfs directory\n");
+       }
+
+       return d_xen_debug;
+}
+
+struct array_data
+{
+       void *array;
+       unsigned elements;
+};
+
+static int u32_array_open(struct inode *inode, struct file *file)
+{
+       file->private_data = NULL;
+       return nonseekable_open(inode, file);
+}
+
+static size_t format_array(char *buf, size_t bufsize, const char *fmt,
+                          u32 *array, unsigned array_size)
+{
+       size_t ret = 0;
+       unsigned i;
+
+       for(i = 0; i < array_size; i++) {
+               size_t len;
+
+               len = snprintf(buf, bufsize, fmt, array[i]);
+               len++;  /* ' ' or '\n' */
+               ret += len;
+
+               if (buf) {
+                       buf += len;
+                       bufsize -= len;
+                       buf[-1] = (i == array_size-1) ? '\n' : ' ';
+               }
+       }
+
+       ret++;          /* \0 */
+       if (buf)
+               *buf = '\0';
+
+       return ret;
+}
+
+static char *format_array_alloc(const char *fmt, u32 *array, unsigned array_size)
+{
+       size_t len = format_array(NULL, 0, fmt, array, array_size);
+       char *ret;
+
+       ret = kmalloc(len, GFP_KERNEL);
+       if (ret == NULL)
+               return NULL;
+
+       format_array(ret, len, fmt, array, array_size);
+       return ret;
+}
+
+static ssize_t u32_array_read(struct file *file, char __user *buf, size_t len,
+                             loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct array_data *data = inode->i_private;
+       size_t size;
+
+       if (*ppos == 0) {
+               if (file->private_data) {
+                       kfree(file->private_data);
+                       file->private_data = NULL;
+               }
+
+               file->private_data = format_array_alloc("%u", data->array, data->elements);
+       }
+
+       size = 0;
+       if (file->private_data)
+               size = strlen(file->private_data);
+
+       return simple_read_from_buffer(buf, len, ppos, file->private_data, size);
+}
+
+static int xen_array_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+
+       return 0;
+}
+
+static struct file_operations u32_array_fops = {
+       .owner  = THIS_MODULE,
+       .open   = u32_array_open,
+       .release= xen_array_release,
+       .read   = u32_array_read,
+};
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+                                           struct dentry *parent,
+                                           u32 *array, unsigned elements)
+{
+       struct array_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
+
+       if (data == NULL)
+               return NULL;
+
+       data->array = array;
+       data->elements = elements;
+
+       return debugfs_create_file(name, mode, parent, data, &u32_array_fops);
+}
diff --git a/arch/x86/xen/debugfs.h b/arch/x86/xen/debugfs.h
new file mode 100644 (file)
index 0000000..e281320
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _XEN_DEBUGFS_H
+#define _XEN_DEBUGFS_H
+
+struct dentry * __init xen_init_debugfs(void);
+
+struct dentry *xen_debugfs_create_u32_array(const char *name, mode_t mode,
+                                           struct dentry *parent,
+                                           u32 *array, unsigned elements);
+
+#endif /* _XEN_DEBUGFS_H */
index a27d562a9744b178bc082882b7ba36bc9f8aed9d..0013a729b41ddc93045510068da9bcbbadf76433 100644 (file)
@@ -30,7 +30,6 @@
 #include <xen/interface/xen.h>
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
-#include <xen/interface/sched.h>
 #include <xen/features.h>
 #include <xen/page.h>
 #include <xen/hvc-console.h>
@@ -58,6 +57,9 @@ EXPORT_SYMBOL_GPL(hypercall_page);
 DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
 DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
 
+enum xen_domain_type xen_domain_type = XEN_NATIVE;
+EXPORT_SYMBOL_GPL(xen_domain_type);
+
 /*
  * Identity map, in addition to plain kernel map.  This needs to be
  * large enough to allocate page table pages to allocate the rest.
@@ -111,7 +113,14 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info;
  *
  * 0: not available, 1: available
  */
-static int have_vcpu_info_placement = 1;
+static int have_vcpu_info_placement =
+#ifdef CONFIG_X86_32
+       1
+#else
+       0
+#endif
+       ;
+
 
 static void xen_vcpu_setup(int cpu)
 {
@@ -227,103 +236,68 @@ static unsigned long xen_get_debugreg(int reg)
        return HYPERVISOR_get_debugreg(reg);
 }
 
-static unsigned long xen_save_fl(void)
+static void xen_leave_lazy(void)
 {
-       struct vcpu_info *vcpu;
-       unsigned long flags;
-
-       vcpu = x86_read_percpu(xen_vcpu);
-
-       /* flag has opposite sense of mask */
-       flags = !vcpu->evtchn_upcall_mask;
-
-       /* convert to IF type flag
-          -0 -> 0x00000000
-          -1 -> 0xffffffff
-       */
-       return (-flags) & X86_EFLAGS_IF;
+       paravirt_leave_lazy(paravirt_get_lazy_mode());
+       xen_mc_flush();
 }
 
-static void xen_restore_fl(unsigned long flags)
+static unsigned long xen_store_tr(void)
 {
-       struct vcpu_info *vcpu;
-
-       /* convert from IF type flag */
-       flags = !(flags & X86_EFLAGS_IF);
-
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
-       preempt_disable();
-       vcpu = x86_read_percpu(xen_vcpu);
-       vcpu->evtchn_upcall_mask = flags;
-       preempt_enable_no_resched();
-
-       /* Doesn't matter if we get preempted here, because any
-          pending event will get dealt with anyway. */
-
-       if (flags == 0) {
-               preempt_check_resched();
-               barrier(); /* unmask then check (avoid races) */
-               if (unlikely(vcpu->evtchn_upcall_pending))
-                       force_evtchn_callback();
-       }
+       return 0;
 }
 
-static void xen_irq_disable(void)
+/*
+ * Set the page permissions for a particular virtual address.  If the
+ * address is a vmalloc mapping (or other non-linear mapping), then
+ * find the linear mapping of the page and also set its protections to
+ * match.
+ */
+static void set_aliased_prot(void *v, pgprot_t prot)
 {
-       /* There's a one instruction preempt window here.  We need to
-          make sure we're don't switch CPUs between getting the vcpu
-          pointer and updating the mask. */
-       preempt_disable();
-       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
-       preempt_enable_no_resched();
-}
+       int level;
+       pte_t *ptep;
+       pte_t pte;
+       unsigned long pfn;
+       struct page *page;
 
-static void xen_irq_enable(void)
-{
-       struct vcpu_info *vcpu;
+       ptep = lookup_address((unsigned long)v, &level);
+       BUG_ON(ptep == NULL);
 
-       /* We don't need to worry about being preempted here, since
-          either a) interrupts are disabled, so no preemption, or b)
-          the caller is confused and is trying to re-enable interrupts
-          on an indeterminate processor. */
+       pfn = pte_pfn(*ptep);
+       page = pfn_to_page(pfn);
 
-       vcpu = x86_read_percpu(xen_vcpu);
-       vcpu->evtchn_upcall_mask = 0;
+       pte = pfn_pte(pfn, prot);
 
-       /* Doesn't matter if we get preempted here, because any
-          pending event will get dealt with anyway. */
+       if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
+               BUG();
 
-       barrier(); /* unmask then check (avoid races) */
-       if (unlikely(vcpu->evtchn_upcall_pending))
-               force_evtchn_callback();
-}
+       if (!PageHighMem(page)) {
+               void *av = __va(PFN_PHYS(pfn));
 
-static void xen_safe_halt(void)
-{
-       /* Blocking includes an implicit local_irq_enable(). */
-       if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
-               BUG();
+               if (av != v)
+                       if (HYPERVISOR_update_va_mapping((unsigned long)av, pte, 0))
+                               BUG();
+       } else
+               kmap_flush_unused();
 }
 
-static void xen_halt(void)
+static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
 {
-       if (irqs_disabled())
-               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
-       else
-               xen_safe_halt();
-}
+       const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+       int i;
 
-static void xen_leave_lazy(void)
-{
-       paravirt_leave_lazy(paravirt_get_lazy_mode());
-       xen_mc_flush();
+       for(i = 0; i < entries; i += entries_per_page)
+               set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
 }
 
-static unsigned long xen_store_tr(void)
+static void xen_free_ldt(struct desc_struct *ldt, unsigned entries)
 {
-       return 0;
+       const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
+       int i;
+
+       for(i = 0; i < entries; i += entries_per_page)
+               set_aliased_prot(ldt + i, PAGE_KERNEL);
 }
 
 static void xen_set_ldt(const void *addr, unsigned entries)
@@ -426,8 +400,7 @@ static void xen_load_gs_index(unsigned int idx)
 static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
                                const void *ptr)
 {
-       unsigned long lp = (unsigned long)&dt[entrynum];
-       xmaddr_t mach_lp = virt_to_machine(lp);
+       xmaddr_t mach_lp = arbitrary_virt_to_machine(&dt[entrynum]);
        u64 entry = *(u64 *)ptr;
 
        preempt_disable();
@@ -560,7 +533,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
 }
 
 static void xen_load_sp0(struct tss_struct *tss,
-                         struct thread_struct *thread)
+                        struct thread_struct *thread)
 {
        struct multicall_space mcs = xen_mc_entry(0);
        MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0);
@@ -835,6 +808,19 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
                        ret = -EFAULT;
                break;
 #endif
+
+       case MSR_STAR:
+       case MSR_CSTAR:
+       case MSR_LSTAR:
+       case MSR_SYSCALL_MASK:
+       case MSR_IA32_SYSENTER_CS:
+       case MSR_IA32_SYSENTER_ESP:
+       case MSR_IA32_SYSENTER_EIP:
+               /* Fast syscall setup is all done in hypercalls, so
+                  these are all ignored.  Stub them out here to stop
+                  Xen console noise. */
+               break;
+
        default:
                ret = native_write_msr_safe(msr, low, high);
        }
@@ -878,8 +864,8 @@ static void xen_alloc_ptpage(struct mm_struct *mm, unsigned long pfn, unsigned l
                SetPagePinned(page);
 
                if (!PageHighMem(page)) {
-                       make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
-                       if (level == PT_PTE)
+                       make_lowmem_page_readonly(__va(PFN_PHYS((unsigned long)pfn)));
+                       if (level == PT_PTE && USE_SPLIT_PTLOCKS)
                                pin_pagetable_pfn(MMUEXT_PIN_L1_TABLE, pfn);
                } else
                        /* make sure there are no stray mappings of
@@ -947,7 +933,7 @@ static void xen_release_ptpage(unsigned long pfn, unsigned level)
 
        if (PagePinned(page)) {
                if (!PageHighMem(page)) {
-                       if (level == PT_PTE)
+                       if (level == PT_PTE && USE_SPLIT_PTLOCKS)
                                pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
                        make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
                }
@@ -994,6 +980,7 @@ static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
 }
 #endif
 
+#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
        /* If there's an existing pte, then don't allow _PAGE_RW to be set */
@@ -1012,6 +999,7 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
 
        xen_set_pte(ptep, pte);
 }
+#endif
 
 static __init void xen_pagetable_setup_start(pgd_t *base)
 {
@@ -1078,7 +1066,6 @@ void xen_setup_vcpu_info_placement(void)
 
        /* xen_vcpu_setup managed to place the vcpu_info within the
           percpu area for all cpus, so make use of it */
-#ifdef CONFIG_X86_32
        if (have_vcpu_info_placement) {
                printk(KERN_INFO "Xen: using vcpu_info placement\n");
 
@@ -1088,7 +1075,6 @@ void xen_setup_vcpu_info_placement(void)
                pv_irq_ops.irq_enable = xen_irq_enable_direct;
                pv_mmu_ops.read_cr2 = xen_read_cr2_direct;
        }
-#endif
 }
 
 static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
@@ -1109,12 +1095,10 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
        goto patch_site
 
        switch (type) {
-#ifdef CONFIG_X86_32
                SITE(pv_irq_ops, irq_enable);
                SITE(pv_irq_ops, irq_disable);
                SITE(pv_irq_ops, save_fl);
                SITE(pv_irq_ops, restore_fl);
-#endif /* CONFIG_X86_32 */
 #undef SITE
 
        patch_site:
@@ -1252,6 +1236,9 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        .load_gs_index = xen_load_gs_index,
 #endif
 
+       .alloc_ldt = xen_alloc_ldt,
+       .free_ldt = xen_free_ldt,
+
        .store_gdt = native_store_gdt,
        .store_idt = native_store_idt,
        .store_tr = xen_store_tr,
@@ -1273,36 +1260,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
        },
 };
 
-static void __init __xen_init_IRQ(void)
-{
-#ifdef CONFIG_X86_64
-       int i;
-
-       /* Create identity vector->irq map */
-       for(i = 0; i < NR_VECTORS; i++) {
-               int cpu;
-
-               for_each_possible_cpu(cpu)
-                       per_cpu(vector_irq, cpu)[i] = i;
-       }
-#endif /* CONFIG_X86_64 */
-
-       xen_init_IRQ();
-}
-
-static const struct pv_irq_ops xen_irq_ops __initdata = {
-       .init_IRQ = __xen_init_IRQ,
-       .save_fl = xen_save_fl,
-       .restore_fl = xen_restore_fl,
-       .irq_disable = xen_irq_disable,
-       .irq_enable = xen_irq_enable,
-       .safe_halt = xen_safe_halt,
-       .halt = xen_halt,
-#ifdef CONFIG_X86_64
-       .adjust_exception_frame = xen_adjust_exception_frame,
-#endif
-};
-
 static const struct pv_apic_ops xen_apic_ops __initdata = {
 #ifdef CONFIG_X86_LOCAL_APIC
        .setup_boot_clock = paravirt_nop,
@@ -1443,7 +1400,7 @@ static void __init xen_reserve_top(void)
        if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
                top = pp.virt_start;
 
-       reserve_top_address(-top + 2 * PAGE_SIZE);
+       reserve_top_address(-top);
 #endif /* CONFIG_X86_32 */
 }
 
@@ -1477,48 +1434,11 @@ static void *m2v(phys_addr_t maddr)
        return __ka(m2p(maddr));
 }
 
-#ifdef CONFIG_X86_64
-static void walk(pgd_t *pgd, unsigned long addr)
-{
-       unsigned l4idx = pgd_index(addr);
-       unsigned l3idx = pud_index(addr);
-       unsigned l2idx = pmd_index(addr);
-       unsigned l1idx = pte_index(addr);
-       pgd_t l4;
-       pud_t l3;
-       pmd_t l2;
-       pte_t l1;
-
-       xen_raw_printk("walk %p, %lx -> %d %d %d %d\n",
-                      pgd, addr, l4idx, l3idx, l2idx, l1idx);
-
-       l4 = pgd[l4idx];
-       xen_raw_printk("  l4: %016lx\n", l4.pgd);
-       xen_raw_printk("      %016lx\n", pgd_val(l4));
-
-       l3 = ((pud_t *)(m2v(l4.pgd)))[l3idx];
-       xen_raw_printk("  l3: %016lx\n", l3.pud);
-       xen_raw_printk("      %016lx\n", pud_val(l3));
-
-       l2 = ((pmd_t *)(m2v(l3.pud)))[l2idx];
-       xen_raw_printk("  l2: %016lx\n", l2.pmd);
-       xen_raw_printk("      %016lx\n", pmd_val(l2));
-
-       l1 = ((pte_t *)(m2v(l2.pmd)))[l1idx];
-       xen_raw_printk("  l1: %016lx\n", l1.pte);
-       xen_raw_printk("      %016lx\n", pte_val(l1));
-}
-#endif
-
 static void set_page_prot(void *addr, pgprot_t prot)
 {
        unsigned long pfn = __pa(addr) >> PAGE_SHIFT;
        pte_t pte = pfn_pte(pfn, prot);
 
-       xen_raw_printk("addr=%p pfn=%lx mfn=%lx prot=%016llx pte=%016llx\n",
-                      addr, pfn, get_phys_to_machine(pfn),
-                      pgprot_val(prot), pte.pte);
-
        if (HYPERVISOR_update_va_mapping((unsigned long)addr, pte, 0))
                BUG();
 }
@@ -1694,6 +1614,8 @@ asmlinkage void __init xen_start_kernel(void)
        if (!xen_start_info)
                return;
 
+       xen_domain_type = XEN_PV_DOMAIN;
+
        BUG_ON(memcmp(xen_start_info->magic, "xen-3", 5) != 0);
 
        xen_setup_features();
@@ -1703,10 +1625,11 @@ asmlinkage void __init xen_start_kernel(void)
        pv_init_ops = xen_init_ops;
        pv_time_ops = xen_time_ops;
        pv_cpu_ops = xen_cpu_ops;
-       pv_irq_ops = xen_irq_ops;
        pv_apic_ops = xen_apic_ops;
        pv_mmu_ops = xen_mmu_ops;
 
+       xen_init_irq_ops();
+
 #ifdef CONFIG_X86_LOCAL_APIC
        /*
         * set up the basic apic ops.
@@ -1737,7 +1660,7 @@ asmlinkage void __init xen_start_kernel(void)
 
        /* Prevent unwanted bits from being set in PTEs. */
        __supported_pte_mask &= ~_PAGE_GLOBAL;
-       if (!is_initial_xendomain())
+       if (!xen_initial_domain())
                __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
 
        /* Don't do the full vcpu_info placement stuff until we have a
@@ -1772,7 +1695,7 @@ asmlinkage void __init xen_start_kernel(void)
        boot_params.hdr.ramdisk_size = xen_start_info->mod_len;
        boot_params.hdr.cmd_line_ptr = __pa(xen_start_info->cmd_line);
 
-       if (!is_initial_xendomain()) {
+       if (!xen_initial_domain()) {
                add_preferred_console("xenboot", 0, NULL);
                add_preferred_console("tty", 0, NULL);
                add_preferred_console("hvc", 0, NULL);
@@ -1780,15 +1703,6 @@ asmlinkage void __init xen_start_kernel(void)
 
        xen_raw_console_write("about to get started...\n");
 
-#if 0
-       xen_raw_printk("&boot_params=%p __pa(&boot_params)=%lx __va(__pa(&boot_params))=%lx\n",
-                      &boot_params, __pa_symbol(&boot_params),
-                      __va(__pa_symbol(&boot_params)));
-
-       walk(pgd, &boot_params);
-       walk(pgd, __va(__pa(&boot_params)));
-#endif
-
        /* Start the world */
 #ifdef CONFIG_X86_32
        i386_start_kernel();
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
new file mode 100644 (file)
index 0000000..28b85ab
--- /dev/null
@@ -0,0 +1,143 @@
+#include <linux/hardirq.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include "xen-ops.h"
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void xen_force_evtchn_callback(void)
+{
+       (void)HYPERVISOR_xen_version(0, NULL);
+}
+
+static void __init __xen_init_IRQ(void)
+{
+#ifdef CONFIG_X86_64
+       int i;
+
+       /* Create identity vector->irq map */
+       for(i = 0; i < NR_VECTORS; i++) {
+               int cpu;
+
+               for_each_possible_cpu(cpu)
+                       per_cpu(vector_irq, cpu)[i] = i;
+       }
+#endif /* CONFIG_X86_64 */
+
+       xen_init_IRQ();
+}
+
+static unsigned long xen_save_fl(void)
+{
+       struct vcpu_info *vcpu;
+       unsigned long flags;
+
+       vcpu = x86_read_percpu(xen_vcpu);
+
+       /* flag has opposite sense of mask */
+       flags = !vcpu->evtchn_upcall_mask;
+
+       /* convert to IF type flag
+          -0 -> 0x00000000
+          -1 -> 0xffffffff
+       */
+       return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+       struct vcpu_info *vcpu;
+
+       /* convert from IF type flag */
+       flags = !(flags & X86_EFLAGS_IF);
+
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = flags;
+       preempt_enable_no_resched();
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       if (flags == 0) {
+               preempt_check_resched();
+               barrier(); /* unmask then check (avoid races) */
+               if (unlikely(vcpu->evtchn_upcall_pending))
+                       xen_force_evtchn_callback();
+       }
+}
+
+static void xen_irq_disable(void)
+{
+       /* There's a one instruction preempt window here.  We need to
+          make sure we're don't switch CPUs between getting the vcpu
+          pointer and updating the mask. */
+       preempt_disable();
+       x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+       preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+       struct vcpu_info *vcpu;
+
+       /* We don't need to worry about being preempted here, since
+          either a) interrupts are disabled, so no preemption, or b)
+          the caller is confused and is trying to re-enable interrupts
+          on an indeterminate processor. */
+
+       vcpu = x86_read_percpu(xen_vcpu);
+       vcpu->evtchn_upcall_mask = 0;
+
+       /* Doesn't matter if we get preempted here, because any
+          pending event will get dealt with anyway. */
+
+       barrier(); /* unmask then check (avoid races) */
+       if (unlikely(vcpu->evtchn_upcall_pending))
+               xen_force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+       /* Blocking includes an implicit local_irq_enable(). */
+       if (HYPERVISOR_sched_op(SCHEDOP_block, NULL) != 0)
+               BUG();
+}
+
+static void xen_halt(void)
+{
+       if (irqs_disabled())
+               HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       else
+               xen_safe_halt();
+}
+
+static const struct pv_irq_ops xen_irq_ops __initdata = {
+       .init_IRQ = __xen_init_IRQ,
+       .save_fl = xen_save_fl,
+       .restore_fl = xen_restore_fl,
+       .irq_disable = xen_irq_disable,
+       .irq_enable = xen_irq_enable,
+       .safe_halt = xen_safe_halt,
+       .halt = xen_halt,
+#ifdef CONFIG_X86_64
+       .adjust_exception_frame = xen_adjust_exception_frame,
+#endif
+};
+
+void __init xen_init_irq_ops()
+{
+       pv_irq_ops = xen_irq_ops;
+}
index aa37469da69691cba0eca23089a517dcab26351a..ae173f6edd8ba044f5cc5372193ea7ce0af2e299 100644 (file)
@@ -40,6 +40,7 @@
  */
 #include <linux/sched.h>
 #include <linux/highmem.h>
+#include <linux/debugfs.h>
 #include <linux/bug.h>
 
 #include <asm/pgtable.h>
 
 #include "multicalls.h"
 #include "mmu.h"
+#include "debugfs.h"
+
+#define MMU_UPDATE_HISTO       30
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct {
+       u32 pgd_update;
+       u32 pgd_update_pinned;
+       u32 pgd_update_batched;
+
+       u32 pud_update;
+       u32 pud_update_pinned;
+       u32 pud_update_batched;
+
+       u32 pmd_update;
+       u32 pmd_update_pinned;
+       u32 pmd_update_batched;
+
+       u32 pte_update;
+       u32 pte_update_pinned;
+       u32 pte_update_batched;
+
+       u32 mmu_update;
+       u32 mmu_update_extended;
+       u32 mmu_update_histo[MMU_UPDATE_HISTO];
+
+       u32 prot_commit;
+       u32 prot_commit_batched;
+
+       u32 set_pte_at;
+       u32 set_pte_at_batched;
+       u32 set_pte_at_pinned;
+       u32 set_pte_at_current;
+       u32 set_pte_at_kernel;
+} mmu_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&mmu_stats, 0, sizeof(mmu_stats));
+               zero_stats = 0;
+       }
+}
+
+#define ADD_STATS(elem, val)                   \
+       do { check_zero(); mmu_stats.elem += (val); } while(0)
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
+
+#endif /* CONFIG_XEN_DEBUG_FS */
 
 /*
  * Just beyond the highest usermode address.  STACK_TOP_MAX has a
@@ -229,25 +285,35 @@ void make_lowmem_page_readwrite(void *vaddr)
 }
 
 
-static bool page_pinned(void *ptr)
+static bool xen_page_pinned(void *ptr)
 {
        struct page *page = virt_to_page(ptr);
 
        return PagePinned(page);
 }
 
-static void extend_mmu_update(const struct mmu_update *update)
+static void xen_extend_mmu_update(const struct mmu_update *update)
 {
        struct multicall_space mcs;
        struct mmu_update *u;
 
        mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
 
-       if (mcs.mc != NULL)
+       if (mcs.mc != NULL) {
+               ADD_STATS(mmu_update_extended, 1);
+               ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
+
                mcs.mc->args[1]++;
-       else {
+
+               if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
+                       ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
+               else
+                       ADD_STATS(mmu_update_histo[0], 1);
+       } else {
+               ADD_STATS(mmu_update, 1);
                mcs = __xen_mc_entry(sizeof(*u));
                MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
+               ADD_STATS(mmu_update_histo[1], 1);
        }
 
        u = mcs.args;
@@ -265,7 +331,9 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
        /* ptr may be ioremapped for 64-bit pagetable setup */
        u.ptr = arbitrary_virt_to_machine(ptr).maddr;
        u.val = pmd_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -274,13 +342,17 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
 
 void xen_set_pmd(pmd_t *ptr, pmd_t val)
 {
+       ADD_STATS(pmd_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                return;
        }
 
+       ADD_STATS(pmd_update_pinned, 1);
+
        xen_set_pmd_hyper(ptr, val);
 }
 
@@ -300,12 +372,18 @@ void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
        if (mm == &init_mm)
                preempt_disable();
 
+       ADD_STATS(set_pte_at, 1);
+//     ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
+       ADD_STATS(set_pte_at_current, mm == current->mm);
+       ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+
        if (mm == current->mm || mm == &init_mm) {
                if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
                        struct multicall_space mcs;
                        mcs = xen_mc_entry(0);
 
                        MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+                       ADD_STATS(set_pte_at_batched, 1);
                        xen_mc_issue(PARAVIRT_LAZY_MMU);
                        goto out;
                } else
@@ -334,7 +412,10 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
 
        u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
        u.val = pte_val_ma(pte);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(prot_commit, 1);
+       ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 }
@@ -400,7 +481,9 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
        /* ptr may be ioremapped for 64-bit pagetable setup */
        u.ptr = arbitrary_virt_to_machine(ptr).maddr;
        u.val = pud_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
+
+       ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
 
        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
@@ -409,18 +492,26 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
 
 void xen_set_pud(pud_t *ptr, pud_t val)
 {
+       ADD_STATS(pud_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                return;
        }
 
+       ADD_STATS(pud_update_pinned, 1);
+
        xen_set_pud_hyper(ptr, val);
 }
 
 void xen_set_pte(pte_t *ptep, pte_t pte)
 {
+       ADD_STATS(pte_update, 1);
+//     ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
+       ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
 #ifdef CONFIG_X86_PAE
        ptep->pte_high = pte.pte_high;
        smp_wmb();
@@ -490,7 +581,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
 
        u.ptr = virt_to_machine(ptr).maddr;
        u.val = pgd_val_ma(val);
-       extend_mmu_update(&u);
+       xen_extend_mmu_update(&u);
 }
 
 /*
@@ -517,17 +608,22 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
 {
        pgd_t *user_ptr = xen_get_user_pgd(ptr);
 
+       ADD_STATS(pgd_update, 1);
+
        /* If page is not pinned, we can just update the entry
           directly */
-       if (!page_pinned(ptr)) {
+       if (!xen_page_pinned(ptr)) {
                *ptr = val;
                if (user_ptr) {
-                       WARN_ON(page_pinned(user_ptr));
+                       WARN_ON(xen_page_pinned(user_ptr));
                        *user_ptr = val;
                }
                return;
        }
 
+       ADD_STATS(pgd_update_pinned, 1);
+       ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
+
        /* If it's pinned, then we can at least batch the kernel and
           user updates together. */
        xen_mc_batch();
@@ -555,9 +651,12 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
  * For 64-bit, we must skip the Xen hole in the middle of the address
  * space, just after the big x86-64 virtual hole.
  */
-static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
-                   unsigned long limit)
+static int xen_pgd_walk(struct mm_struct *mm,
+                       int (*func)(struct mm_struct *mm, struct page *,
+                                   enum pt_level),
+                       unsigned long limit)
 {
+       pgd_t *pgd = mm->pgd;
        int flush = 0;
        unsigned hole_low, hole_high;
        unsigned pgdidx_limit, pudidx_limit, pmdidx_limit;
@@ -590,8 +689,6 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
        pmdidx_limit = 0;
 #endif
 
-       flush |= (*func)(virt_to_page(pgd), PT_PGD);
-
        for (pgdidx = 0; pgdidx <= pgdidx_limit; pgdidx++) {
                pud_t *pud;
 
@@ -604,7 +701,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                pud = pud_offset(&pgd[pgdidx], 0);
 
                if (PTRS_PER_PUD > 1) /* not folded */
-                       flush |= (*func)(virt_to_page(pud), PT_PUD);
+                       flush |= (*func)(mm, virt_to_page(pud), PT_PUD);
 
                for (pudidx = 0; pudidx < PTRS_PER_PUD; pudidx++) {
                        pmd_t *pmd;
@@ -619,7 +716,7 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                        pmd = pmd_offset(&pud[pudidx], 0);
 
                        if (PTRS_PER_PMD > 1) /* not folded */
-                               flush |= (*func)(virt_to_page(pmd), PT_PMD);
+                               flush |= (*func)(mm, virt_to_page(pmd), PT_PMD);
 
                        for (pmdidx = 0; pmdidx < PTRS_PER_PMD; pmdidx++) {
                                struct page *pte;
@@ -633,28 +730,34 @@ static int pgd_walk(pgd_t *pgd, int (*func)(struct page *, enum pt_level),
                                        continue;
 
                                pte = pmd_page(pmd[pmdidx]);
-                               flush |= (*func)(pte, PT_PTE);
+                               flush |= (*func)(mm, pte, PT_PTE);
                        }
                }
        }
+
 out:
+       /* Do the top level last, so that the callbacks can use it as
+          a cue to do final things like tlb flushes. */
+       flush |= (*func)(mm, virt_to_page(pgd), PT_PGD);
 
        return flush;
 }
 
-static spinlock_t *lock_pte(struct page *page)
+/* If we're using split pte locks, then take the page's lock and
+   return a pointer to it.  Otherwise return NULL. */
+static spinlock_t *xen_pte_lock(struct page *page, struct mm_struct *mm)
 {
        spinlock_t *ptl = NULL;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
        ptl = __pte_lockptr(page);
-       spin_lock(ptl);
+       spin_lock_nest_lock(ptl, &mm->page_table_lock);
 #endif
 
        return ptl;
 }
 
-static void do_unlock(void *v)
+static void xen_pte_unlock(void *v)
 {
        spinlock_t *ptl = v;
        spin_unlock(ptl);
@@ -672,7 +775,8 @@ static void xen_do_pin(unsigned level, unsigned long pfn)
        MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
 }
 
-static int pin_page(struct page *page, enum pt_level level)
+static int xen_pin_page(struct mm_struct *mm, struct page *page,
+                       enum pt_level level)
 {
        unsigned pgfl = TestSetPagePinned(page);
        int flush;
@@ -691,21 +795,40 @@ static int pin_page(struct page *page, enum pt_level level)
 
                flush = 0;
 
+               /*
+                * We need to hold the pagetable lock between the time
+                * we make the pagetable RO and when we actually pin
+                * it.  If we don't, then other users may come in and
+                * attempt to update the pagetable by writing it,
+                * which will fail because the memory is RO but not
+                * pinned, so Xen won't do the trap'n'emulate.
+                *
+                * If we're using split pte locks, we can't hold the
+                * entire pagetable's worth of locks during the
+                * traverse, because we may wrap the preempt count (8
+                * bits).  The solution is to mark RO and pin each PTE
+                * page while holding the lock.  This means the number
+                * of locks we end up holding is never more than a
+                * batch size (~32 entries, at present).
+                *
+                * If we're not using split pte locks, we needn't pin
+                * the PTE pages independently, because we're
+                * protected by the overall pagetable lock.
+                */
                ptl = NULL;
                if (level == PT_PTE)
-                       ptl = lock_pte(page);
+                       ptl = xen_pte_lock(page, mm);
 
                MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
                                        pfn_pte(pfn, PAGE_KERNEL_RO),
                                        level == PT_PGD ? UVMF_TLB_FLUSH : 0);
 
-               if (level == PT_PTE)
+               if (ptl) {
                        xen_do_pin(MMUEXT_PIN_L1_TABLE, pfn);
 
-               if (ptl) {
                        /* Queue a deferred unlock for when this batch
                           is completed. */
-                       xen_mc_callback(do_unlock, ptl);
+                       xen_mc_callback(xen_pte_unlock, ptl);
                }
        }
 
@@ -715,11 +838,11 @@ static int pin_page(struct page *page, enum pt_level level)
 /* This is called just after a mm has been created, but it has not
    been used yet.  We need to make sure that its pagetable is all
    read-only, and can be pinned. */
-void xen_pgd_pin(pgd_t *pgd)
+static void __xen_pgd_pin(struct mm_struct *mm, pgd_t *pgd)
 {
        xen_mc_batch();
 
-       if (pgd_walk(pgd, pin_page, USER_LIMIT)) {
+       if (xen_pgd_walk(mm, xen_pin_page, USER_LIMIT)) {
                /* re-enable interrupts for kmap_flush_unused */
                xen_mc_issue(0);
                kmap_flush_unused();
@@ -733,25 +856,35 @@ void xen_pgd_pin(pgd_t *pgd)
                xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(pgd)));
 
                if (user_pgd) {
-                       pin_page(virt_to_page(user_pgd), PT_PGD);
+                       xen_pin_page(mm, virt_to_page(user_pgd), PT_PGD);
                        xen_do_pin(MMUEXT_PIN_L4_TABLE, PFN_DOWN(__pa(user_pgd)));
                }
        }
 #else /* CONFIG_X86_32 */
 #ifdef CONFIG_X86_PAE
        /* Need to make sure unshared kernel PMD is pinnable */
-       pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+       xen_pin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+                    PT_PMD);
 #endif
        xen_do_pin(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(pgd)));
 #endif /* CONFIG_X86_64 */
        xen_mc_issue(0);
 }
 
+static void xen_pgd_pin(struct mm_struct *mm)
+{
+       __xen_pgd_pin(mm, mm->pgd);
+}
+
 /*
  * On save, we need to pin all pagetables to make sure they get their
  * mfns turned into pfns.  Search the list for any unpinned pgds and pin
  * them (unpinned pgds are not currently in use, probably because the
  * process is under construction or destruction).
+ *
+ * Expected to be called in stop_machine() ("equivalent to taking
+ * every spinlock in the system"), so the locking doesn't really
+ * matter all that much.
  */
 void xen_mm_pin_all(void)
 {
@@ -762,7 +895,7 @@ void xen_mm_pin_all(void)
 
        list_for_each_entry(page, &pgd_list, lru) {
                if (!PagePinned(page)) {
-                       xen_pgd_pin((pgd_t *)page_address(page));
+                       __xen_pgd_pin(&init_mm, (pgd_t *)page_address(page));
                        SetPageSavePinned(page);
                }
        }
@@ -775,7 +908,8 @@ void xen_mm_pin_all(void)
  * that's before we have page structures to store the bits.  So do all
  * the book-keeping now.
  */
-static __init int mark_pinned(struct page *page, enum pt_level level)
+static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+                                 enum pt_level level)
 {
        SetPagePinned(page);
        return 0;
@@ -783,10 +917,11 @@ static __init int mark_pinned(struct page *page, enum pt_level level)
 
 void __init xen_mark_init_mm_pinned(void)
 {
-       pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+       xen_pgd_walk(&init_mm, xen_mark_pinned, FIXADDR_TOP);
 }
 
-static int unpin_page(struct page *page, enum pt_level level)
+static int xen_unpin_page(struct mm_struct *mm, struct page *page,
+                         enum pt_level level)
 {
        unsigned pgfl = TestClearPagePinned(page);
 
@@ -796,10 +931,18 @@ static int unpin_page(struct page *page, enum pt_level level)
                spinlock_t *ptl = NULL;
                struct multicall_space mcs;
 
+               /*
+                * Do the converse to pin_page.  If we're using split
+                * pte locks, we must be holding the lock for while
+                * the pte page is unpinned but still RO to prevent
+                * concurrent updates from seeing it in this
+                * partially-pinned state.
+                */
                if (level == PT_PTE) {
-                       ptl = lock_pte(page);
+                       ptl = xen_pte_lock(page, mm);
 
-                       xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
+                       if (ptl)
+                               xen_do_pin(MMUEXT_UNPIN_TABLE, pfn);
                }
 
                mcs = __xen_mc_entry(0);
@@ -810,7 +953,7 @@ static int unpin_page(struct page *page, enum pt_level level)
 
                if (ptl) {
                        /* unlock when batch completed */
-                       xen_mc_callback(do_unlock, ptl);
+                       xen_mc_callback(xen_pte_unlock, ptl);
                }
        }
 
@@ -818,7 +961,7 @@ static int unpin_page(struct page *page, enum pt_level level)
 }
 
 /* Release a pagetables pages back as normal RW */
-static void xen_pgd_unpin(pgd_t *pgd)
+static void __xen_pgd_unpin(struct mm_struct *mm, pgd_t *pgd)
 {
        xen_mc_batch();
 
@@ -830,21 +973,27 @@ static void xen_pgd_unpin(pgd_t *pgd)
 
                if (user_pgd) {
                        xen_do_pin(MMUEXT_UNPIN_TABLE, PFN_DOWN(__pa(user_pgd)));
-                       unpin_page(virt_to_page(user_pgd), PT_PGD);
+                       xen_unpin_page(mm, virt_to_page(user_pgd), PT_PGD);
                }
        }
 #endif
 
 #ifdef CONFIG_X86_PAE
        /* Need to make sure unshared kernel PMD is unpinned */
-       pin_page(virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])), PT_PMD);
+       xen_unpin_page(mm, virt_to_page(pgd_page(pgd[pgd_index(TASK_SIZE)])),
+                      PT_PMD);
 #endif
 
-       pgd_walk(pgd, unpin_page, USER_LIMIT);
+       xen_pgd_walk(mm, xen_unpin_page, USER_LIMIT);
 
        xen_mc_issue(0);
 }
 
+static void xen_pgd_unpin(struct mm_struct *mm)
+{
+       __xen_pgd_unpin(mm, mm->pgd);
+}
+
 /*
  * On resume, undo any pinning done at save, so that the rest of the
  * kernel doesn't see any unexpected pinned pagetables.
@@ -859,7 +1008,7 @@ void xen_mm_unpin_all(void)
        list_for_each_entry(page, &pgd_list, lru) {
                if (PageSavePinned(page)) {
                        BUG_ON(!PagePinned(page));
-                       xen_pgd_unpin((pgd_t *)page_address(page));
+                       __xen_pgd_unpin(&init_mm, (pgd_t *)page_address(page));
                        ClearPageSavePinned(page);
                }
        }
@@ -870,14 +1019,14 @@ void xen_mm_unpin_all(void)
 void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        spin_lock(&next->page_table_lock);
-       xen_pgd_pin(next->pgd);
+       xen_pgd_pin(next);
        spin_unlock(&next->page_table_lock);
 }
 
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
 {
        spin_lock(&mm->page_table_lock);
-       xen_pgd_pin(mm->pgd);
+       xen_pgd_pin(mm);
        spin_unlock(&mm->page_table_lock);
 }
 
@@ -907,7 +1056,7 @@ static void drop_other_mm_ref(void *info)
        }
 }
 
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
        cpumask_t mask;
        unsigned cpu;
@@ -937,7 +1086,7 @@ static void drop_mm_ref(struct mm_struct *mm)
                smp_call_function_mask(mask, drop_other_mm_ref, mm, 1);
 }
 #else
-static void drop_mm_ref(struct mm_struct *mm)
+static void xen_drop_mm_ref(struct mm_struct *mm)
 {
        if (current->active_mm == mm)
                load_cr3(swapper_pg_dir);
@@ -961,14 +1110,77 @@ static void drop_mm_ref(struct mm_struct *mm)
 void xen_exit_mmap(struct mm_struct *mm)
 {
        get_cpu();              /* make sure we don't move around */
-       drop_mm_ref(mm);
+       xen_drop_mm_ref(mm);
        put_cpu();
 
        spin_lock(&mm->page_table_lock);
 
        /* pgd may not be pinned in the error exit path of execve */
-       if (page_pinned(mm->pgd))
-               xen_pgd_unpin(mm->pgd);
+       if (xen_page_pinned(mm->pgd))
+               xen_pgd_unpin(mm);
 
        spin_unlock(&mm->page_table_lock);
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mmu_debug;
+
+static int __init xen_mmu_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_mmu_debug = debugfs_create_dir("mmu", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
+
+       debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
+       debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pgd_update_pinned);
+       debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pgd_update_pinned);
+
+       debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
+       debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pud_update_pinned);
+       debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pud_update_pinned);
+
+       debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
+       debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
+                          &mmu_stats.pmd_update_pinned);
+       debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pmd_update_pinned);
+
+       debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
+//     debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
+//                        &mmu_stats.pte_update_pinned);
+       debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
+                          &mmu_stats.pte_update_pinned);
+
+       debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
+       debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
+                          &mmu_stats.mmu_update_extended);
+       xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
+                                    mmu_stats.mmu_update_histo, 20);
+
+       debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
+       debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_batched);
+       debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_current);
+       debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
+                          &mmu_stats.set_pte_at_kernel);
+
+       debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
+       debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
+                          &mmu_stats.prot_commit_batched);
+
+       return 0;
+}
+fs_initcall(xen_mmu_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index 0f59bd03f9e31f9ac8316e452b21729b0d4de9cb..98d71659da5a15ceb21a08f090d1c457d52df775 100644 (file)
@@ -18,9 +18,6 @@ void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
 void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
 void xen_exit_mmap(struct mm_struct *mm);
 
-void xen_pgd_pin(pgd_t *pgd);
-//void xen_pgd_unpin(pgd_t *pgd);
-
 pteval_t xen_pte_val(pte_t);
 pmdval_t xen_pmd_val(pmd_t);
 pgdval_t xen_pgd_val(pgd_t);
index 9efd1c6c9776c5f9e8973026dd03b111c6e9e585..8ea8a0d0b0deeff69a438a5ad4fc0552d250d68f 100644 (file)
  */
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
+#include <linux/debugfs.h>
 
 #include <asm/xen/hypercall.h>
 
 #include "multicalls.h"
+#include "debugfs.h"
+
+#define MC_BATCH       32
 
 #define MC_DEBUG       1
 
-#define MC_BATCH       32
 #define MC_ARGS                (MC_BATCH * 16)
 
+
 struct mc_buffer {
        struct multicall_entry entries[MC_BATCH];
 #if MC_DEBUG
@@ -47,6 +51,76 @@ struct mc_buffer {
 static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
 DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
 
+/* flush reasons 0- slots, 1- args, 2- callbacks */
+enum flush_reasons
+{
+       FL_SLOTS,
+       FL_ARGS,
+       FL_CALLBACKS,
+
+       FL_N_REASONS
+};
+
+#ifdef CONFIG_XEN_DEBUG_FS
+#define NHYPERCALLS    40              /* not really */
+
+static struct {
+       unsigned histo[MC_BATCH+1];
+
+       unsigned issued;
+       unsigned arg_total;
+       unsigned hypercalls;
+       unsigned histo_hypercalls[NHYPERCALLS];
+
+       unsigned flush[FL_N_REASONS];
+} mc_stats;
+
+static u8 zero_stats;
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&mc_stats, 0, sizeof(mc_stats));
+               zero_stats = 0;
+       }
+}
+
+static void mc_add_stats(const struct mc_buffer *mc)
+{
+       int i;
+
+       check_zero();
+
+       mc_stats.issued++;
+       mc_stats.hypercalls += mc->mcidx;
+       mc_stats.arg_total += mc->argidx;
+
+       mc_stats.histo[mc->mcidx]++;
+       for(i = 0; i < mc->mcidx; i++) {
+               unsigned op = mc->entries[i].op;
+               if (op < NHYPERCALLS)
+                       mc_stats.histo_hypercalls[op]++;
+       }
+}
+
+static void mc_stats_flush(enum flush_reasons idx)
+{
+       check_zero();
+
+       mc_stats.flush[idx]++;
+}
+
+#else  /* !CONFIG_XEN_DEBUG_FS */
+
+static inline void mc_add_stats(const struct mc_buffer *mc)
+{
+}
+
+static inline void mc_stats_flush(enum flush_reasons idx)
+{
+}
+#endif /* CONFIG_XEN_DEBUG_FS */
+
 void xen_mc_flush(void)
 {
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
@@ -60,6 +134,8 @@ void xen_mc_flush(void)
           something in the middle */
        local_irq_save(flags);
 
+       mc_add_stats(b);
+
        if (b->mcidx) {
 #if MC_DEBUG
                memcpy(b->debug, b->entries,
@@ -115,6 +191,7 @@ struct multicall_space __xen_mc_entry(size_t args)
 
        if (b->mcidx == MC_BATCH ||
            (argidx + args) > MC_ARGS) {
+               mc_stats_flush(b->mcidx == MC_BATCH ? FL_SLOTS : FL_ARGS);
                xen_mc_flush();
                argidx = roundup(b->argidx, sizeof(u64));
        }
@@ -158,10 +235,44 @@ void xen_mc_callback(void (*fn)(void *), void *data)
        struct mc_buffer *b = &__get_cpu_var(mc_buffer);
        struct callback *cb;
 
-       if (b->cbidx == MC_BATCH)
+       if (b->cbidx == MC_BATCH) {
+               mc_stats_flush(FL_CALLBACKS);
                xen_mc_flush();
+       }
 
        cb = &b->callbacks[b->cbidx++];
        cb->fn = fn;
        cb->data = data;
 }
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_mc_debug;
+
+static int __init xen_mc_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_mc_debug = debugfs_create_dir("multicalls", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_mc_debug, &zero_stats);
+
+       debugfs_create_u32("batches", 0444, d_mc_debug, &mc_stats.issued);
+       debugfs_create_u32("hypercalls", 0444, d_mc_debug, &mc_stats.hypercalls);
+       debugfs_create_u32("arg_total", 0444, d_mc_debug, &mc_stats.arg_total);
+
+       xen_debugfs_create_u32_array("batch_histo", 0444, d_mc_debug,
+                                    mc_stats.histo, MC_BATCH);
+       xen_debugfs_create_u32_array("hypercall_histo", 0444, d_mc_debug,
+                                    mc_stats.histo_hypercalls, NHYPERCALLS);
+       xen_debugfs_create_u32_array("flush_reasons", 0444, d_mc_debug,
+                                    mc_stats.flush, FL_N_REASONS);
+
+       return 0;
+}
+fs_initcall(xen_mc_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index d8faf79a0a1da22b57d4f39ee58abc1ca9b908d7..d77da613b1d2e49e626e601a6cdb9027d807fb18 100644 (file)
  * useful topology information for the kernel to make use of.  As a
  * result, all CPUs are treated as if they're single-core and
  * single-threaded.
- *
- * This does not handle HOTPLUG_CPU yet.
  */
 #include <linux/sched.h>
-#include <linux/kernel_stat.h>
 #include <linux/err.h>
 #include <linux/smp.h>
 
@@ -36,8 +33,6 @@
 #include "xen-ops.h"
 #include "mmu.h"
 
-static void __cpuinit xen_init_lock_cpu(int cpu);
-
 cpumask_t xen_cpu_initialized_map;
 
 static DEFINE_PER_CPU(int, resched_irq);
@@ -64,11 +59,12 @@ static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static __cpuinit void cpu_bringup_and_idle(void)
+static __cpuinit void cpu_bringup(void)
 {
        int cpu = smp_processor_id();
 
        cpu_init();
+       touch_softlockup_watchdog();
        preempt_disable();
 
        xen_enable_sysenter();
@@ -89,6 +85,11 @@ static __cpuinit void cpu_bringup_and_idle(void)
        local_irq_enable();
 
        wmb();                  /* make sure everything is out */
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+       cpu_bringup();
        cpu_idle();
 }
 
@@ -212,8 +213,6 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
 
                cpu_set(cpu, cpu_present_map);
        }
-
-       //init_xenbus_allowed_cpumask();
 }
 
 static __cpuinit int
@@ -281,12 +280,6 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
        struct task_struct *idle = idle_task(cpu);
        int rc;
 
-#if 0
-       rc = cpu_up_check(cpu);
-       if (rc)
-               return rc;
-#endif
-
 #ifdef CONFIG_X86_64
        /* Allocate node local memory for AP pdas */
        WARN_ON(cpu == 0);
@@ -339,6 +332,60 @@ static void xen_smp_cpus_done(unsigned int max_cpus)
 {
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int xen_cpu_disable(void)
+{
+       unsigned int cpu = smp_processor_id();
+       if (cpu == 0)
+               return -EBUSY;
+
+       cpu_disable_common();
+
+       load_cr3(swapper_pg_dir);
+       return 0;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+       while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout(HZ/10);
+       }
+       unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(debug_irq, cpu), NULL);
+       unbind_from_irqhandler(per_cpu(callfuncsingle_irq, cpu), NULL);
+       xen_uninit_lock_cpu(cpu);
+       xen_teardown_timer(cpu);
+
+       if (num_online_cpus() == 1)
+               alternatives_smp_switch(0);
+}
+
+static void xen_play_dead(void)
+{
+       play_dead_common();
+       HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+       cpu_bringup();
+}
+
+#else /* !CONFIG_HOTPLUG_CPU */
+static int xen_cpu_disable(void)
+{
+       return -ENOSYS;
+}
+
+static void xen_cpu_die(unsigned int cpu)
+{
+       BUG();
+}
+
+static void xen_play_dead(void)
+{
+       BUG();
+}
+
+#endif
 static void stop_self(void *v)
 {
        int cpu = smp_processor_id();
@@ -419,176 +466,16 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-struct xen_spinlock {
-       unsigned char lock;             /* 0 -> free; 1 -> locked */
-       unsigned short spinners;        /* count of waiting cpus */
-};
-
-static int xen_spin_is_locked(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       return xl->lock != 0;
-}
-
-static int xen_spin_is_contended(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       /* Not strictly true; this is only the count of contended
-          lock-takers entering the slow path. */
-       return xl->spinners != 0;
-}
-
-static int xen_spin_trylock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       u8 old = 1;
-
-       asm("xchgb %b0,%1"
-           : "+q" (old), "+m" (xl->lock) : : "memory");
-
-       return old == 0;
-}
-
-static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
-static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
-
-static inline void spinning_lock(struct xen_spinlock *xl)
-{
-       __get_cpu_var(lock_spinners) = xl;
-       wmb();                  /* set lock of interest before count */
-       asm(LOCK_PREFIX " incw %0"
-           : "+m" (xl->spinners) : : "memory");
-}
-
-static inline void unspinning_lock(struct xen_spinlock *xl)
-{
-       asm(LOCK_PREFIX " decw %0"
-           : "+m" (xl->spinners) : : "memory");
-       wmb();                  /* decrement count before clearing lock */
-       __get_cpu_var(lock_spinners) = NULL;
-}
-
-static noinline int xen_spin_lock_slow(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       int irq = __get_cpu_var(lock_kicker_irq);
-       int ret;
-
-       /* If kicker interrupts not initialized yet, just spin */
-       if (irq == -1)
-               return 0;
-
-       /* announce we're spinning */
-       spinning_lock(xl);
-
-       /* clear pending */
-       xen_clear_irq_pending(irq);
-
-       /* check again make sure it didn't become free while
-          we weren't looking  */
-       ret = xen_spin_trylock(lock);
-       if (ret)
-               goto out;
-
-       /* block until irq becomes pending */
-       xen_poll_irq(irq);
-       kstat_this_cpu.irqs[irq]++;
-
-out:
-       unspinning_lock(xl);
-       return ret;
-}
-
-static void xen_spin_lock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-       int timeout;
-       u8 oldval;
-
-       do {
-               timeout = 1 << 10;
-
-               asm("1: xchgb %1,%0\n"
-                   "   testb %1,%1\n"
-                   "   jz 3f\n"
-                   "2: rep;nop\n"
-                   "   cmpb $0,%0\n"
-                   "   je 1b\n"
-                   "   dec %2\n"
-                   "   jnz 2b\n"
-                   "3:\n"
-                   : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
-                   : "1" (1)
-                   : "memory");
-
-       } while (unlikely(oldval != 0 && !xen_spin_lock_slow(lock)));
-}
-
-static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
-{
-       int cpu;
-
-       for_each_online_cpu(cpu) {
-               /* XXX should mix up next cpu selection */
-               if (per_cpu(lock_spinners, cpu) == xl) {
-                       xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
-                       break;
-               }
-       }
-}
-
-static void xen_spin_unlock(struct raw_spinlock *lock)
-{
-       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
-
-       smp_wmb();              /* make sure no writes get moved after unlock */
-       xl->lock = 0;           /* release lock */
-
-       /* make sure unlock happens before kick */
-       barrier();
-
-       if (unlikely(xl->spinners))
-               xen_spin_unlock_slow(xl);
-}
-
-static __cpuinit void xen_init_lock_cpu(int cpu)
-{
-       int irq;
-       const char *name;
-
-       name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
-       irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
-                                    cpu,
-                                    xen_reschedule_interrupt,
-                                    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
-                                    name,
-                                    NULL);
-
-       if (irq >= 0) {
-               disable_irq(irq); /* make sure it's never delivered */
-               per_cpu(lock_kicker_irq, cpu) = irq;
-       }
-
-       printk("cpu %d spinlock event irq %d\n", cpu, irq);
-}
-
-static void __init xen_init_spinlocks(void)
-{
-       pv_lock_ops.spin_is_locked = xen_spin_is_locked;
-       pv_lock_ops.spin_is_contended = xen_spin_is_contended;
-       pv_lock_ops.spin_lock = xen_spin_lock;
-       pv_lock_ops.spin_trylock = xen_spin_trylock;
-       pv_lock_ops.spin_unlock = xen_spin_unlock;
-}
-
 static const struct smp_ops xen_smp_ops __initdata = {
        .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
        .smp_prepare_cpus = xen_smp_prepare_cpus,
-       .cpu_up = xen_cpu_up,
        .smp_cpus_done = xen_smp_cpus_done,
 
+       .cpu_up = xen_cpu_up,
+       .cpu_die = xen_cpu_die,
+       .cpu_disable = xen_cpu_disable,
+       .play_dead = xen_play_dead,
+
        .smp_send_stop = xen_smp_send_stop,
        .smp_send_reschedule = xen_smp_send_reschedule,
 
diff --git a/arch/x86/xen/spinlock.c b/arch/x86/xen/spinlock.c
new file mode 100644 (file)
index 0000000..dd71e3a
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Split spinlock implementation out into its own file, so it can be
+ * compiled in a FTRACE-compatible way.
+ */
+#include <linux/kernel_stat.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/log2.h>
+
+#include <asm/paravirt.h>
+
+#include <xen/interface/xen.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "debugfs.h"
+
+#ifdef CONFIG_XEN_DEBUG_FS
+static struct xen_spinlock_stats
+{
+       u64 taken;
+       u32 taken_slow;
+       u32 taken_slow_nested;
+       u32 taken_slow_pickup;
+       u32 taken_slow_spurious;
+       u32 taken_slow_irqenable;
+
+       u64 released;
+       u32 released_slow;
+       u32 released_slow_kicked;
+
+#define HISTO_BUCKETS  30
+       u32 histo_spin_total[HISTO_BUCKETS+1];
+       u32 histo_spin_spinning[HISTO_BUCKETS+1];
+       u32 histo_spin_blocked[HISTO_BUCKETS+1];
+
+       u64 time_total;
+       u64 time_spinning;
+       u64 time_blocked;
+} spinlock_stats;
+
+static u8 zero_stats;
+
+static unsigned lock_timeout = 1 << 10;
+#define TIMEOUT lock_timeout
+
+static inline void check_zero(void)
+{
+       if (unlikely(zero_stats)) {
+               memset(&spinlock_stats, 0, sizeof(spinlock_stats));
+               zero_stats = 0;
+       }
+}
+
+#define ADD_STATS(elem, val)                   \
+       do { check_zero(); spinlock_stats.elem += (val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+       return xen_clocksource_read();
+}
+
+static void __spin_time_accum(u64 delta, u32 *array)
+{
+       unsigned index = ilog2(delta);
+
+       check_zero();
+
+       if (index < HISTO_BUCKETS)
+               array[index]++;
+       else
+               array[HISTO_BUCKETS]++;
+}
+
+static inline void spin_time_accum_spinning(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_spinning);
+       spinlock_stats.time_spinning += delta;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_total);
+       spinlock_stats.time_total += delta;
+}
+
+static inline void spin_time_accum_blocked(u64 start)
+{
+       u32 delta = xen_clocksource_read() - start;
+
+       __spin_time_accum(delta, spinlock_stats.histo_spin_blocked);
+       spinlock_stats.time_blocked += delta;
+}
+#else  /* !CONFIG_XEN_DEBUG_FS */
+#define TIMEOUT                        (1 << 10)
+#define ADD_STATS(elem, val)   do { (void)(val); } while(0)
+
+static inline u64 spin_time_start(void)
+{
+       return 0;
+}
+
+static inline void spin_time_accum_total(u64 start)
+{
+}
+static inline void spin_time_accum_spinning(u64 start)
+{
+}
+static inline void spin_time_accum_blocked(u64 start)
+{
+}
+#endif  /* CONFIG_XEN_DEBUG_FS */
+
+struct xen_spinlock {
+       unsigned char lock;             /* 0 -> free; 1 -> locked */
+       unsigned short spinners;        /* count of waiting cpus */
+};
+
+static int xen_spin_is_locked(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       return xl->lock != 0;
+}
+
+static int xen_spin_is_contended(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       /* Not strictly true; this is only the count of contended
+          lock-takers entering the slow path. */
+       return xl->spinners != 0;
+}
+
+static int xen_spin_trylock(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       u8 old = 1;
+
+       asm("xchgb %b0,%1"
+           : "+q" (old), "+m" (xl->lock) : : "memory");
+
+       return old == 0;
+}
+
+static DEFINE_PER_CPU(int, lock_kicker_irq) = -1;
+static DEFINE_PER_CPU(struct xen_spinlock *, lock_spinners);
+
+/*
+ * Mark a cpu as interested in a lock.  Returns the CPU's previous
+ * lock of interest, in case we got preempted by an interrupt.
+ */
+static inline struct xen_spinlock *spinning_lock(struct xen_spinlock *xl)
+{
+       struct xen_spinlock *prev;
+
+       prev = __get_cpu_var(lock_spinners);
+       __get_cpu_var(lock_spinners) = xl;
+
+       wmb();                  /* set lock of interest before count */
+
+       asm(LOCK_PREFIX " incw %0"
+           : "+m" (xl->spinners) : : "memory");
+
+       return prev;
+}
+
+/*
+ * Mark a cpu as no longer interested in a lock.  Restores previous
+ * lock of interest (NULL for none).
+ */
+static inline void unspinning_lock(struct xen_spinlock *xl, struct xen_spinlock *prev)
+{
+       asm(LOCK_PREFIX " decw %0"
+           : "+m" (xl->spinners) : : "memory");
+       wmb();                  /* decrement count before restoring lock */
+       __get_cpu_var(lock_spinners) = prev;
+}
+
+static noinline int xen_spin_lock_slow(struct raw_spinlock *lock, bool irq_enable)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       struct xen_spinlock *prev;
+       int irq = __get_cpu_var(lock_kicker_irq);
+       int ret;
+       unsigned long flags;
+       u64 start;
+
+       /* If kicker interrupts not initialized yet, just spin */
+       if (irq == -1)
+               return 0;
+
+       start = spin_time_start();
+
+       /* announce we're spinning */
+       prev = spinning_lock(xl);
+
+       flags = __raw_local_save_flags();
+       if (irq_enable) {
+               ADD_STATS(taken_slow_irqenable, 1);
+               raw_local_irq_enable();
+       }
+
+       ADD_STATS(taken_slow, 1);
+       ADD_STATS(taken_slow_nested, prev != NULL);
+
+       do {
+               /* clear pending */
+               xen_clear_irq_pending(irq);
+
+               /* check again make sure it didn't become free while
+                  we weren't looking  */
+               ret = xen_spin_trylock(lock);
+               if (ret) {
+                       ADD_STATS(taken_slow_pickup, 1);
+
+                       /*
+                        * If we interrupted another spinlock while it
+                        * was blocking, make sure it doesn't block
+                        * without rechecking the lock.
+                        */
+                       if (prev != NULL)
+                               xen_set_irq_pending(irq);
+                       goto out;
+               }
+
+               /*
+                * Block until irq becomes pending.  If we're
+                * interrupted at this point (after the trylock but
+                * before entering the block), then the nested lock
+                * handler guarantees that the irq will be left
+                * pending if there's any chance the lock became free;
+                * xen_poll_irq() returns immediately if the irq is
+                * pending.
+                */
+               xen_poll_irq(irq);
+               ADD_STATS(taken_slow_spurious, !xen_test_irq_pending(irq));
+       } while (!xen_test_irq_pending(irq)); /* check for spurious wakeups */
+
+       kstat_this_cpu.irqs[irq]++;
+
+out:
+       raw_local_irq_restore(flags);
+       unspinning_lock(xl, prev);
+       spin_time_accum_blocked(start);
+
+       return ret;
+}
+
+static inline void __xen_spin_lock(struct raw_spinlock *lock, bool irq_enable)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+       unsigned timeout;
+       u8 oldval;
+       u64 start_spin;
+
+       ADD_STATS(taken, 1);
+
+       start_spin = spin_time_start();
+
+       do {
+               u64 start_spin_fast = spin_time_start();
+
+               timeout = TIMEOUT;
+
+               asm("1: xchgb %1,%0\n"
+                   "   testb %1,%1\n"
+                   "   jz 3f\n"
+                   "2: rep;nop\n"
+                   "   cmpb $0,%0\n"
+                   "   je 1b\n"
+                   "   dec %2\n"
+                   "   jnz 2b\n"
+                   "3:\n"
+                   : "+m" (xl->lock), "=q" (oldval), "+r" (timeout)
+                   : "1" (1)
+                   : "memory");
+
+               spin_time_accum_spinning(start_spin_fast);
+
+       } while (unlikely(oldval != 0 &&
+                         (TIMEOUT == ~0 || !xen_spin_lock_slow(lock, irq_enable))));
+
+       spin_time_accum_total(start_spin);
+}
+
+static void xen_spin_lock(struct raw_spinlock *lock)
+{
+       __xen_spin_lock(lock, false);
+}
+
+static void xen_spin_lock_flags(struct raw_spinlock *lock, unsigned long flags)
+{
+       __xen_spin_lock(lock, !raw_irqs_disabled_flags(flags));
+}
+
+static noinline void xen_spin_unlock_slow(struct xen_spinlock *xl)
+{
+       int cpu;
+
+       ADD_STATS(released_slow, 1);
+
+       for_each_online_cpu(cpu) {
+               /* XXX should mix up next cpu selection */
+               if (per_cpu(lock_spinners, cpu) == xl) {
+                       ADD_STATS(released_slow_kicked, 1);
+                       xen_send_IPI_one(cpu, XEN_SPIN_UNLOCK_VECTOR);
+                       break;
+               }
+       }
+}
+
+static void xen_spin_unlock(struct raw_spinlock *lock)
+{
+       struct xen_spinlock *xl = (struct xen_spinlock *)lock;
+
+       ADD_STATS(released, 1);
+
+       smp_wmb();              /* make sure no writes get moved after unlock */
+       xl->lock = 0;           /* release lock */
+
+       /* make sure unlock happens before kick */
+       barrier();
+
+       if (unlikely(xl->spinners))
+               xen_spin_unlock_slow(xl);
+}
+
+static irqreturn_t dummy_handler(int irq, void *dev_id)
+{
+       BUG();
+       return IRQ_HANDLED;
+}
+
+void __cpuinit xen_init_lock_cpu(int cpu)
+{
+       int irq;
+       const char *name;
+
+       name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
+       irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
+                                    cpu,
+                                    dummy_handler,
+                                    IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                    name,
+                                    NULL);
+
+       if (irq >= 0) {
+               disable_irq(irq); /* make sure it's never delivered */
+               per_cpu(lock_kicker_irq, cpu) = irq;
+       }
+
+       printk("cpu %d spinlock event irq %d\n", cpu, irq);
+}
+
+void xen_uninit_lock_cpu(int cpu)
+{
+       unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
+}
+
+void __init xen_init_spinlocks(void)
+{
+       pv_lock_ops.spin_is_locked = xen_spin_is_locked;
+       pv_lock_ops.spin_is_contended = xen_spin_is_contended;
+       pv_lock_ops.spin_lock = xen_spin_lock;
+       pv_lock_ops.spin_lock_flags = xen_spin_lock_flags;
+       pv_lock_ops.spin_trylock = xen_spin_trylock;
+       pv_lock_ops.spin_unlock = xen_spin_unlock;
+}
+
+#ifdef CONFIG_XEN_DEBUG_FS
+
+static struct dentry *d_spin_debug;
+
+static int __init xen_spinlock_debugfs(void)
+{
+       struct dentry *d_xen = xen_init_debugfs();
+
+       if (d_xen == NULL)
+               return -ENOMEM;
+
+       d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
+
+       debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
+
+       debugfs_create_u32("timeout", 0644, d_spin_debug, &lock_timeout);
+
+       debugfs_create_u64("taken", 0444, d_spin_debug, &spinlock_stats.taken);
+       debugfs_create_u32("taken_slow", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow);
+       debugfs_create_u32("taken_slow_nested", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_nested);
+       debugfs_create_u32("taken_slow_pickup", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_pickup);
+       debugfs_create_u32("taken_slow_spurious", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_spurious);
+       debugfs_create_u32("taken_slow_irqenable", 0444, d_spin_debug,
+                          &spinlock_stats.taken_slow_irqenable);
+
+       debugfs_create_u64("released", 0444, d_spin_debug, &spinlock_stats.released);
+       debugfs_create_u32("released_slow", 0444, d_spin_debug,
+                          &spinlock_stats.released_slow);
+       debugfs_create_u32("released_slow_kicked", 0444, d_spin_debug,
+                          &spinlock_stats.released_slow_kicked);
+
+       debugfs_create_u64("time_spinning", 0444, d_spin_debug,
+                          &spinlock_stats.time_spinning);
+       debugfs_create_u64("time_blocked", 0444, d_spin_debug,
+                          &spinlock_stats.time_blocked);
+       debugfs_create_u64("time_total", 0444, d_spin_debug,
+                          &spinlock_stats.time_total);
+
+       xen_debugfs_create_u32_array("histo_total", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_total, HISTO_BUCKETS + 1);
+       xen_debugfs_create_u32_array("histo_spinning", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_spinning, HISTO_BUCKETS + 1);
+       xen_debugfs_create_u32_array("histo_blocked", 0444, d_spin_debug,
+                                    spinlock_stats.histo_spin_blocked, HISTO_BUCKETS + 1);
+
+       return 0;
+}
+fs_initcall(xen_spinlock_debugfs);
+
+#endif /* CONFIG_XEN_DEBUG_FS */
index 685b77470fc3612c45549018303808cb5cf628f3..004ba86326ae022eb1b9d60a926a9adc6f207582 100644 (file)
@@ -30,8 +30,6 @@
 #define TIMER_SLOP     100000
 #define NS_PER_TICK    (1000000000LL / HZ)
 
-static cycle_t xen_clocksource_read(void);
-
 /* runstate info updated by Xen */
 static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
 
@@ -213,7 +211,7 @@ unsigned long xen_tsc_khz(void)
        return xen_khz;
 }
 
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
 {
         struct pvclock_vcpu_time_info *src;
        cycle_t ret;
@@ -452,6 +450,14 @@ void xen_setup_timer(int cpu)
        setup_runstate_info(cpu);
 }
 
+void xen_teardown_timer(int cpu)
+{
+       struct clock_event_device *evt;
+       BUG_ON(cpu == 0);
+       evt = &per_cpu(xen_clock_events, cpu);
+       unbind_from_irqhandler(evt->irq, NULL);
+}
+
 void xen_setup_cpu_clockevents(void)
 {
        BUG_ON(preemptible());
index 2497a30f41de0331b93c5f36df5804013a68ee9b..42786f59d9c0016f84413e61d8312ffae63c0a6c 100644 (file)
@@ -298,7 +298,7 @@ check_events:
        push %eax
        push %ecx
        push %edx
-       call force_evtchn_callback
+       call xen_force_evtchn_callback
        pop %edx
        pop %ecx
        pop %eax
index 7f58304fafb3098fc68d35be4d9c02206077e8cb..05794c566e8799382f9a314970661d5ab232e4a8 100644 (file)
 /* Pseudo-flag used for virtual NMI, which we don't implement yet */
 #define XEN_EFLAGS_NMI 0x80000000
 
-#if 0
-#include <asm/percpu.h>
+#if 1
+/*
+       x86-64 does not yet support direct access to percpu variables
+       via a segment override, so we just need to make sure this code
+       never gets used
+ */
+#define BUG                    ud2a
+#define PER_CPU_VAR(var, off)  0xdeadbeef
+#endif
 
 /*
        Enable events.  This clears the event mask and tests the pending
@@ -35,6 +42,8 @@
        events, then enter the hypervisor to get them handled.
  */
 ENTRY(xen_irq_enable_direct)
+       BUG
+
        /* Unmask events */
        movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 
@@ -58,6 +67,8 @@ ENDPATCH(xen_irq_enable_direct)
        non-zero.
  */
 ENTRY(xen_irq_disable_direct)
+       BUG
+
        movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
 ENDPATCH(xen_irq_disable_direct)
        ret
@@ -74,6 +85,8 @@ ENDPATCH(xen_irq_disable_direct)
        Xen and x86 use opposite senses (mask vs enable).
  */
 ENTRY(xen_save_fl_direct)
+       BUG
+
        testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
        setz %ah
        addb %ah,%ah
@@ -91,6 +104,8 @@ ENDPATCH(xen_save_fl_direct)
        if so.
  */
 ENTRY(xen_restore_fl_direct)
+       BUG
+
        testb $X86_EFLAGS_IF>>8, %ah
        setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask)
        /* Preempt here doesn't matter because that will deal with
@@ -122,7 +137,7 @@ check_events:
        push %r9
        push %r10
        push %r11
-       call force_evtchn_callback
+       call xen_force_evtchn_callback
        pop %r11
        pop %r10
        pop %r9
@@ -133,7 +148,6 @@ check_events:
        pop %rcx
        pop %rax
        ret
-#endif
 
 ENTRY(xen_adjust_exception_frame)
        mov 8+0(%rsp),%rcx
index dd3c23152a2e618f733192c86aac1ad04de61ed9..d7422dc2a55c33fd1a77cee38fc877110ff3a24e 100644 (file)
@@ -2,6 +2,7 @@
 #define XEN_OPS_H
 
 #include <linux/init.h>
+#include <linux/clocksource.h>
 #include <linux/irqreturn.h>
 #include <xen/xen-ops.h>
 
@@ -31,7 +32,10 @@ void xen_vcpu_restore(void);
 
 void __init xen_build_dynamic_phys_to_machine(void);
 
+void xen_init_irq_ops(void);
 void xen_setup_timer(int cpu);
+void xen_teardown_timer(int cpu);
+cycle_t xen_clocksource_read(void);
 void xen_setup_cpu_clockevents(void);
 unsigned long xen_tsc_khz(void);
 void __init xen_time_init(void);
@@ -50,6 +54,10 @@ void __init xen_setup_vcpu_info_placement(void);
 #ifdef CONFIG_SMP
 void xen_smp_init(void);
 
+void __init xen_init_spinlocks(void);
+__cpuinit void xen_init_lock_cpu(int cpu);
+void xen_uninit_lock_cpu(int cpu);
+
 extern cpumask_t xen_cpu_initialized_map;
 #else
 static inline void xen_smp_init(void) {}
index 8dd3336efd7e242209240010b7fa9710bb2ae6e8..3c578ef78c4830f791039b83e2a44ab80d7538d8 100644 (file)
@@ -369,7 +369,6 @@ static int __init acpi_rtc_init(void)
                DBG("RTC unavailable?\n");
        return 0;
 }
-/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */
-fs_initcall(acpi_rtc_init);
+module_init(acpi_rtc_init);
 
 #endif
index f17cd4b572f87324b2d261b491fc1f9f78d8d696..78fbec8ceda0452c83b715e1d86bc593be8eb3cf 100644 (file)
@@ -7,7 +7,6 @@ menuconfig ATA
        depends on HAS_IOMEM
        depends on BLOCK
        depends on !(M32R || M68K) || BROKEN
-       depends on !SUN4 || BROKEN
        select SCSI
        ---help---
          If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
index 73338d231db9f232c90a5fcbbbe432ad50687044..937c9c0ef4c9a10baaf38991849c00094389f3fa 100644 (file)
@@ -47,8 +47,9 @@
 #include <asm/atomic.h>
 
 #ifdef CONFIG_SBUS
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
@@ -661,249 +662,189 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
 
 #ifdef CONFIG_SBUS
 
-static u32
-fore200e_sba_read(volatile u32 __iomem *addr)
+static u32 fore200e_sba_read(volatile u32 __iomem *addr)
 {
     return sbus_readl(addr);
 }
 
-
-static void
-fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
+static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
 {
     sbus_writel(val, addr);
 }
 
-
-static u32
-fore200e_sba_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
+static u32 fore200e_sba_dma_map(struct fore200e *fore200e, void* virt_addr, int size, int direction)
 {
-    u32 dma_addr = sbus_map_single((struct sbus_dev*)fore200e->bus_dev, virt_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
+       u32 dma_addr;
 
-    DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
-           virt_addr, size, direction, dma_addr);
+       dma_addr = dma_map_single(&op->dev, virt_addr, size, direction);
+
+       DPRINTK(3, "SBUS DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d --> dma_addr = 0x%08x\n",
+               virt_addr, size, direction, dma_addr);
     
-    return dma_addr;
+       return dma_addr;
 }
 
-
-static void
-fore200e_sba_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_unmap(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
-           dma_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
 
-    sbus_unmap_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+       DPRINTK(3, "SBUS DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d,\n",
+               dma_addr, size, direction);
 
+       dma_unmap_single(&op->dev, dma_addr, size, direction);
+}
 
-static void
-fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_cpu(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
+       struct of_device *op = fore200e->bus_dev;
+
+       DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
     
-    sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
+       dma_sync_single_for_cpu(&op->dev, dma_addr, size, direction);
 }
 
-static void
-fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction)
+static void fore200e_sba_dma_sync_for_device(struct fore200e *fore200e, u32 dma_addr, int size, int direction)
 {
-    DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
-
-    sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
 
-/* allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
-   (to hold descriptors, status, queues, etc.) shared by the driver and the adapter */
+       dma_sync_single_for_device(&op->dev, dma_addr, size, direction);
+}
 
-static int
-fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
-                            int size, int nbr, int alignment)
+/* Allocate a DVMA consistent chunk of memory intended to act as a communication mechanism
+ * (to hold descriptors, status, queues, etc.) shared by the driver and the adapter.
+ */
+static int fore200e_sba_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
+                                       int size, int nbr, int alignment)
 {
-    chunk->alloc_size = chunk->align_size = size * nbr;
+       struct of_device *op = fore200e->bus_dev;
 
-    /* returned chunks are page-aligned */
-    chunk->alloc_addr = sbus_alloc_consistent((struct sbus_dev*)fore200e->bus_dev,
-                                             chunk->alloc_size,
-                                             &chunk->dma_addr);
+       chunk->alloc_size = chunk->align_size = size * nbr;
 
-    if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
-       return -ENOMEM;
+       /* returned chunks are page-aligned */
+       chunk->alloc_addr = dma_alloc_coherent(&op->dev, chunk->alloc_size,
+                                              &chunk->dma_addr, GFP_ATOMIC);
 
-    chunk->align_addr = chunk->alloc_addr;
+       if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
+               return -ENOMEM;
+
+       chunk->align_addr = chunk->alloc_addr;
     
-    return 0;
+       return 0;
 }
 
-
 /* free a DVMA consistent chunk of memory */
-
-static void
-fore200e_sba_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
+static void fore200e_sba_dma_chunk_free(struct fore200e *fore200e, struct chunk *chunk)
 {
-    sbus_free_consistent((struct sbus_dev*)fore200e->bus_dev,
-                        chunk->alloc_size,
-                        chunk->alloc_addr,
-                        chunk->dma_addr);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       dma_free_coherent(&op->dev, chunk->alloc_size,
+                         chunk->alloc_addr, chunk->dma_addr);
+}
 
-static void
-fore200e_sba_irq_enable(struct fore200e* fore200e)
+static void fore200e_sba_irq_enable(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
+       u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+       fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
 }
 
-
-static int
-fore200e_sba_irq_check(struct fore200e* fore200e)
+static int fore200e_sba_irq_check(struct fore200e *fore200e)
 {
-    return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
+       return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
 }
 
-
-static void
-fore200e_sba_irq_ack(struct fore200e* fore200e)
+static void fore200e_sba_irq_ack(struct fore200e *fore200e)
 {
-    u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
-    fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
+       u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
+       fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
 }
 
-
-static void
-fore200e_sba_reset(struct fore200e* fore200e)
+static void fore200e_sba_reset(struct fore200e *fore200e)
 {
-    fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
-    fore200e_spin(10);
-    fore200e->bus->write(0, fore200e->regs.sba.hcr);
+       fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
+       fore200e_spin(10);
+       fore200e->bus->write(0, fore200e->regs.sba.hcr);
 }
 
-
-static int __init
-fore200e_sba_map(struct fore200e* fore200e)
+static int __init fore200e_sba_map(struct fore200e *fore200e)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-    unsigned int bursts;
+       struct of_device *op = fore200e->bus_dev;
+       unsigned int bursts;
 
-    /* gain access to the SBA specific registers  */
-    fore200e->regs.sba.hcr = sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
-    fore200e->regs.sba.bsr = sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
-    fore200e->regs.sba.isr = sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
-    fore200e->virt_base    = sbus_ioremap(&sbus_dev->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
+       /* gain access to the SBA specific registers  */
+       fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
+       fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
+       fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
+       fore200e->virt_base    = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");
 
-    if (fore200e->virt_base == NULL) {
-       printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
-       return -EFAULT;
-    }
+       if (!fore200e->virt_base) {
+               printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
+               return -EFAULT;
+       }
 
-    DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
+       DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
     
-    fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
+       fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */
 
-    /* get the supported DVMA burst sizes */
-    bursts = prom_getintdefault(sbus_dev->bus->prom_node, "burst-sizes", 0x00);
+       /* get the supported DVMA burst sizes */
+       bursts = of_getintprop_default(op->node->parent, "burst-sizes", 0x00);
 
-    if (sbus_can_dma_64bit(sbus_dev))
-       sbus_set_sbus64(sbus_dev, bursts);
+       if (sbus_can_dma_64bit())
+               sbus_set_sbus64(&op->dev, bursts);
 
-    fore200e->state = FORE200E_STATE_MAP;
-    return 0;
+       fore200e->state = FORE200E_STATE_MAP;
+       return 0;
 }
 
-
-static void
-fore200e_sba_unmap(struct fore200e* fore200e)
+static void fore200e_sba_unmap(struct fore200e *fore200e)
 {
-    sbus_iounmap(fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
-    sbus_iounmap(fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
-    sbus_iounmap(fore200e->virt_base,    SBA200E_RAM_LENGTH);
-}
+       struct of_device *op = fore200e->bus_dev;
 
+       of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
+       of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
+       of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
+       of_iounmap(&op->resource[3], fore200e->virt_base,    SBA200E_RAM_LENGTH);
+}
 
-static int __init
-fore200e_sba_configure(struct fore200e* fore200e)
+static int __init fore200e_sba_configure(struct fore200e *fore200e)
 {
-    fore200e->state = FORE200E_STATE_CONFIGURE;
-    return 0;
+       fore200e->state = FORE200E_STATE_CONFIGURE;
+       return 0;
 }
 
-
-static struct fore200e* __init
-fore200e_sba_detect(const struct fore200e_bus* bus, int index)
+static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
 {
-    struct fore200e*          fore200e;
-    struct sbus_bus* sbus_bus;
-    struct sbus_dev* sbus_dev = NULL;
-    
-    unsigned int     count = 0;
-    
-    for_each_sbus (sbus_bus) {
-       for_each_sbusdev (sbus_dev, sbus_bus) {
-           if (strcmp(sbus_dev->prom_name, SBA200E_PROM_NAME) == 0) {
-               if (count >= index)
-                   goto found;
-               count++;
-           }
-       }
-    }
-    return NULL;
-    
-  found:
-    if (sbus_dev->num_registers != 4) {
-       printk(FORE200E "this %s device has %d instead of 4 registers\n",
-              bus->model_name, sbus_dev->num_registers);
-       return NULL;
-    }
-
-    fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
-    if (fore200e == NULL)
-       return NULL;
+       struct of_device *op = fore200e->bus_dev;
+       const u8 *prop;
+       int len;
 
-    fore200e->bus     = bus;
-    fore200e->bus_dev = sbus_dev;
-    fore200e->irq     = sbus_dev->irqs[ 0 ];
+       prop = of_get_property(op->node, "madaddrlo2", &len);
+       if (!prop)
+               return -ENODEV;
+       memcpy(&prom->mac_addr[4], prop, 4);
 
-    fore200e->phys_base = (unsigned long)sbus_dev;
+       prop = of_get_property(op->node, "madaddrhi4", &len);
+       if (!prop)
+               return -ENODEV;
+       memcpy(&prom->mac_addr[2], prop, 4);
 
-    sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
+       prom->serial_number = of_getintprop_default(op->node, "serialnumber", 0);
+       prom->hw_revision = of_getintprop_default(op->node, "promversion", 0);
     
-    return fore200e;
+       return 0;
 }
 
-
-static int __init
-fore200e_sba_prom_read(struct fore200e* fore200e, struct prom_data* prom)
+static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
 {
-    struct sbus_dev* sbus_dev = (struct sbus_dev*) fore200e->bus_dev;
-    int                       len;
-
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrlo2", &prom->mac_addr[ 4 ], 4);
-    if (len < 0)
-       return -EBUSY;
-
-    len = prom_getproperty(sbus_dev->prom_node, "macaddrhi4", &prom->mac_addr[ 2 ], 4);
-    if (len < 0)
-       return -EBUSY;
-    
-    prom_getproperty(sbus_dev->prom_node, "serialnumber",
-                    (char*)&prom->serial_number, sizeof(prom->serial_number));
-    
-    prom_getproperty(sbus_dev->prom_node, "promversion",
-                    (char*)&prom->hw_revision, sizeof(prom->hw_revision));
-    
-    return 0;
-}
+       struct of_device *op = fore200e->bus_dev;
+       const struct linux_prom_registers *regs;
 
+       regs = of_get_property(op->node, "reg", NULL);
 
-static int
-fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
-{
-    struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
-
-    return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n", sbus_dev->slot, sbus_dev->prom_name);
+       return sprintf(page, "   SBUS slot/device:\t\t%d/'%s'\n",
+                      (regs ? regs->which_io : 0), op->node->name);
 }
 #endif /* CONFIG_SBUS */
 
@@ -2572,7 +2513,7 @@ fore200e_load_and_start_fw(struct fore200e* fore200e)
        device = &((struct pci_dev *) fore200e->bus_dev)->dev;
 #ifdef CONFIG_SBUS
     else if (strcmp(fore200e->bus->model_name, "SBA-200E") == 0)
-       device = &((struct sbus_dev *) fore200e->bus_dev)->ofdev.dev;
+       device = &((struct of_device *) fore200e->bus_dev)->dev;
 #endif
     else
        return err;
@@ -2701,6 +2642,66 @@ fore200e_init(struct fore200e* fore200e)
     return 0;
 }
 
+#ifdef CONFIG_SBUS
+static int __devinit fore200e_sba_probe(struct of_device *op,
+                                       const struct of_device_id *match)
+{
+       const struct fore200e_bus *bus = match->data;
+       struct fore200e *fore200e;
+       static int index = 0;
+       int err;
+
+       fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
+       if (!fore200e)
+               return -ENOMEM;
+
+       fore200e->bus = bus;
+       fore200e->bus_dev = op;
+       fore200e->irq = op->irqs[0];
+       fore200e->phys_base = op->resource[0].start;
+
+       sprintf(fore200e->name, "%s-%d", bus->model_name, index);
+
+       err = fore200e_init(fore200e);
+       if (err < 0) {
+               fore200e_shutdown(fore200e);
+               kfree(fore200e);
+               return err;
+       }
+
+       index++;
+       dev_set_drvdata(&op->dev, fore200e);
+
+       return 0;
+}
+
+static int __devexit fore200e_sba_remove(struct of_device *op)
+{
+       struct fore200e *fore200e = dev_get_drvdata(&op->dev);
+
+       fore200e_shutdown(fore200e);
+       kfree(fore200e);
+
+       return 0;
+}
+
+static const struct of_device_id fore200e_sba_match[] = {
+       {
+               .name = SBA200E_PROM_NAME,
+               .data = (void *) &fore200e_bus[1],
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, fore200e_sba_match);
+
+static struct of_platform_driver fore200e_sba_driver = {
+       .name           = "fore_200e",
+       .match_table    = fore200e_sba_match,
+       .probe          = fore200e_sba_probe,
+       .remove         = __devexit_p(fore200e_sba_remove),
+};
+#endif
+
 #ifdef CONFIG_PCI
 static int __devinit
 fore200e_pca_detect(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
@@ -2784,67 +2785,40 @@ static struct pci_driver fore200e_pca_driver = {
 };
 #endif
 
-
-static int __init
-fore200e_module_init(void)
+static int __init fore200e_module_init(void)
 {
-    const struct fore200e_bus* bus;
-    struct       fore200e*     fore200e;
-    int                        index;
-
-    printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
+       int err;
 
-    /* for each configured bus interface */
-    for (bus = fore200e_bus; bus->model_name; bus++) {
+       printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
 
-       /* detect all boards present on that bus */
-       for (index = 0; bus->detect && (fore200e = bus->detect(bus, index)); index++) {
-           
-           printk(FORE200E "device %s found at 0x%lx, IRQ %s\n",
-                  fore200e->bus->model_name, 
-                  fore200e->phys_base, fore200e_irq_itoa(fore200e->irq));
-
-           sprintf(fore200e->name, "%s-%d", bus->model_name, index);
-
-           if (fore200e_init(fore200e) < 0) {
-
-               fore200e_shutdown(fore200e);
-               break;
-           }
-
-           list_add(&fore200e->entry, &fore200e_boards);
-       }
-    }
+#ifdef CONFIG_SBUS
+       err = of_register_driver(&fore200e_sba_driver, &of_bus_type);
+       if (err)
+               return err;
+#endif
 
 #ifdef CONFIG_PCI
-    if (!pci_register_driver(&fore200e_pca_driver))
-       return 0;
+       err = pci_register_driver(&fore200e_pca_driver);
 #endif
 
-    if (!list_empty(&fore200e_boards))
-       return 0;
+#ifdef CONFIG_SBUS
+       if (err)
+               of_unregister_driver(&fore200e_sba_driver);
+#endif
 
-    return -ENODEV;
+       return err;
 }
 
-
-static void __exit
-fore200e_module_cleanup(void)
+static void __exit fore200e_module_cleanup(void)
 {
-    struct fore200e *fore200e, *next;
-
 #ifdef CONFIG_PCI
-    pci_unregister_driver(&fore200e_pca_driver);
+       pci_unregister_driver(&fore200e_pca_driver);
+#endif
+#ifdef CONFIG_SBUS
+       of_unregister_driver(&fore200e_sba_driver);
 #endif
-
-    list_for_each_entry_safe(fore200e, next, &fore200e_boards, entry) {
-       fore200e_shutdown(fore200e);
-       kfree(fore200e);
-    }
-    DPRINTK(1, "module being removed\n");
 }
 
-
 static int
 fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
 {
@@ -3163,7 +3137,6 @@ static const struct fore200e_bus fore200e_bus[] = {
       fore200e_pca_dma_sync_for_device,
       fore200e_pca_dma_chunk_alloc,
       fore200e_pca_dma_chunk_free,
-      NULL,
       fore200e_pca_configure,
       fore200e_pca_map,
       fore200e_pca_reset,
@@ -3185,7 +3158,6 @@ static const struct fore200e_bus fore200e_bus[] = {
       fore200e_sba_dma_sync_for_device,
       fore200e_sba_dma_chunk_alloc,
       fore200e_sba_dma_chunk_free,
-      fore200e_sba_detect, 
       fore200e_sba_configure,
       fore200e_sba_map,
       fore200e_sba_reset,
index 5c6e7adcb19c99f1be5358bebc4a9a2111291de1..7f97c09aaea5ec068d83c37e2ed2222af601f43a 100644 (file)
@@ -778,9 +778,9 @@ typedef struct fore200e_pca_regs {
 /* SBA-200E registers */
 
 typedef struct fore200e_sba_regs {
-    volatile u32 __iomem *hcr;    /* address of host control register              */
-    volatile u32 __iomem *bsr;    /* address of burst transfer size register       */
-    volatile u32 __iomem *isr;    /* address of interrupt level selection register */
+    u32 __iomem *hcr;    /* address of host control register              */
+    u32 __iomem *bsr;    /* address of burst transfer size register       */
+    u32 __iomem *isr;    /* address of interrupt level selection register */
 } fore200e_sba_regs_t;
 
 
@@ -810,7 +810,6 @@ typedef struct fore200e_bus {
     void                 (*dma_sync_for_device)(struct fore200e*, u32, int, int);
     int                  (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int);
     void                 (*dma_chunk_free)(struct fore200e*, struct chunk*);
-    struct fore200e*     (*detect)(const struct fore200e_bus*, int);
     int                  (*configure)(struct fore200e*); 
     int                  (*map)(struct fore200e*); 
     void                 (*reset)(struct fore200e*);
index a8de037ecd4ac7b5ab3e56f48f6f15400b196463..953c0b83d758dac91a17b409d48d5636a7b62579 100644 (file)
@@ -1,6 +1,6 @@
 /* sunvdc.c: Sun LDOM Virtual Disk Client.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -834,7 +834,7 @@ static int vdc_port_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id vdc_port_match[] = {
+static const struct vio_device_id vdc_port_match[] = {
        {
                .type = "vdc-port",
        },
index bff602ccccf3f66865ea1769fc3b66bbb00162f1..1a50ae70f716a28d2ca2146196fa4fc60f7e1f1a 100644 (file)
@@ -1066,7 +1066,7 @@ static struct xenbus_driver blkfront = {
 
 static int __init xlblk_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
index 6b70aa66a587883bf56f4ca3163ac7828afc3eae..538ceea5e7df364a1f059a482b6cc0adc1d68bc6 100644 (file)
@@ -108,8 +108,8 @@ static int __init xen_init(void)
 {
        struct hvc_struct *hp;
 
-       if (!is_running_on_xen() ||
-           is_initial_xendomain() ||
+       if (!xen_pv_domain() ||
+           xen_initial_domain() ||
            !xen_start_info->console.domU.evtchn)
                return -ENODEV;
 
@@ -142,7 +142,7 @@ static void __exit xen_fini(void)
 
 static int xen_cons_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_pv_domain())
                return 0;
 
        hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
index 5220f541df25e8be038a4a598d6cb82610351a7f..8859aeac2d2510ef6a2a79ea13e364e47f301461 100644 (file)
@@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id n2rng_match[] = {
+static const struct of_device_id n2rng_match[] = {
        {
                .name           = "random-number-generator",
                .compatible     = "SUNW,n2-rng",
index f53d4d00faf01ba76e46d8f99f94048230bd142d..b47710c178855399395b40b41edbc140981df683 100644 (file)
 #endif
 
 #ifdef CONFIG_SPARC32
-#include <linux/pci.h>
-#include <linux/jiffies.h>
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/io.h>
 
 static unsigned long rtc_port;
-static int rtc_irq = PCI_IRQ_NONE;
+static int rtc_irq;
 #endif
 
 #ifdef CONFIG_HPET_RTC_IRQ
@@ -973,8 +973,8 @@ static int __init rtc_init(void)
        char *guess = NULL;
 #endif
 #ifdef CONFIG_SPARC32
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
+       struct device_node *ebus_dp;
+       struct of_device *op;
 #else
        void *r;
 #ifdef RTC_IRQ
@@ -983,12 +983,16 @@ static int __init rtc_init(void)
 #endif
 
 #ifdef CONFIG_SPARC32
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (strcmp(edev->prom_node->name, "rtc") == 0) {
-                               rtc_port = edev->resource[0].start;
-                               rtc_irq = edev->irqs[0];
-                               goto found;
+       for_each_node_by_name(ebus_dp, "ebus") {
+               struct device_node *dp;
+               for (dp = ebus_dp; dp; dp = dp->sibling) {
+                       if (!strcmp(dp->name, "rtc")) {
+                               op = of_find_device_by_node(dp);
+                               if (op) {
+                                       rtc_port = op->resource[0].start;
+                                       rtc_irq = op->irqs[0];
+                                       goto found;
+                               }
                        }
                }
        }
@@ -997,7 +1001,7 @@ static int __init rtc_init(void)
        return -EIO;
 
 found:
-       if (rtc_irq == PCI_IRQ_NONE) {
+       if (!rtc_irq) {
                rtc_has_irq = 0;
                goto no_irq;
        }
index 3309e862f31735e6e44ad61eeac1760f6e349fc0..ebacc0af40fe7e8cba2cbd9cc5ee8d0a1e337bb2 100644 (file)
@@ -800,6 +800,13 @@ config SENSORS_W83627EHF
          This driver can also be built as a module.  If so, the module
          will be called w83627ehf.
 
+config SENSORS_ULTRA45
+       tristate "Sun Ultra45 PIC16F747"
+       depends on SPARC64
+       help
+         This driver provides support for the Ultra45 workstation environmental
+         sensors.
+
 config SENSORS_HDAPS
        tristate "IBM Hard Drive Active Protection System (hdaps)"
        depends on INPUT && X86
index 6babc801b3484139eb68b32a23630ca54136c77d..042d5a78622e4614a397983b147109ff4e01ab20 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SENSORS_FSCHMD)  += fschmd.o
 obj-$(CONFIG_SENSORS_FSCPOS)   += fscpos.o
 obj-$(CONFIG_SENSORS_GL518SM)  += gl518sm.o
 obj-$(CONFIG_SENSORS_GL520SM)  += gl520sm.o
+obj-$(CONFIG_SENSORS_ULTRA45)  += ultra45_env.o
 obj-$(CONFIG_SENSORS_HDAPS)    += hdaps.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
new file mode 100644 (file)
index 0000000..68e90ab
--- /dev/null
@@ -0,0 +1,320 @@
+/* ultra45_env.c: Driver for Ultra45 PIC16F747 environmental monitor.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/io.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#define DRV_MODULE_VERSION     "0.1"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Ultra45 environmental monitor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* PIC device registers */
+#define REG_CMD                0x00UL
+#define  REG_CMD_RESET 0x80
+#define  REG_CMD_ESTAR 0x01
+#define REG_STAT       0x01UL
+#define  REG_STAT_FWVER        0xf0
+#define  REG_STAT_TGOOD        0x08
+#define  REG_STAT_STALE        0x04
+#define  REG_STAT_BUSY 0x02
+#define  REG_STAT_FAULT        0x01
+#define REG_DATA       0x40UL
+#define REG_ADDR       0x41UL
+#define REG_SIZE       0x42UL
+
+/* Registers accessed indirectly via REG_DATA/REG_ADDR */
+#define IREG_FAN0              0x00
+#define IREG_FAN1              0x01
+#define IREG_FAN2              0x02
+#define IREG_FAN3              0x03
+#define IREG_FAN4              0x04
+#define IREG_FAN5              0x05
+#define IREG_LCL_TEMP          0x06
+#define IREG_RMT1_TEMP         0x07
+#define IREG_RMT2_TEMP         0x08
+#define IREG_RMT3_TEMP         0x09
+#define IREG_LM95221_TEMP      0x0a
+#define IREG_FIRE_TEMP         0x0b
+#define IREG_LSI1064_TEMP      0x0c
+#define IREG_FRONT_TEMP                0x0d
+#define IREG_FAN_STAT          0x0e
+#define IREG_VCORE0            0x0f
+#define IREG_VCORE1            0x10
+#define IREG_VMEM0             0x11
+#define IREG_VMEM1             0x12
+#define IREG_PSU_TEMP          0x13
+
+struct env {
+       void __iomem    *regs;
+       spinlock_t      lock;
+
+       struct device   *hwmon_dev;
+};
+
+static u8 env_read(struct env *p, u8 ireg)
+{
+       u8 ret;
+
+       spin_lock(&p->lock);
+       writeb(ireg, p->regs + REG_ADDR);
+       ret = readb(p->regs + REG_DATA);
+       spin_unlock(&p->lock);
+
+       return ret;
+}
+
+static void env_write(struct env *p, u8 ireg, u8 val)
+{
+       spin_lock(&p->lock);
+       writeb(ireg, p->regs + REG_ADDR);
+       writeb(val, p->regs + REG_DATA);
+       spin_unlock(&p->lock);
+}
+
+/* There seems to be a adr7462 providing these values, thus a lot
+ * of these calculations are borrowed from the adt7470 driver.
+ */
+#define FAN_PERIOD_TO_RPM(x)   ((90000 * 60) / (x))
+#define FAN_RPM_TO_PERIOD      FAN_PERIOD_TO_RPM
+#define FAN_PERIOD_INVALID     (0xff << 8)
+#define FAN_DATA_VALID(x)      ((x) && (x) != FAN_PERIOD_INVALID)
+
+static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       int rpm, period;
+       u8 val;
+
+       val = env_read(p, IREG_FAN0 + fan_nr);
+       period = (int) val << 8;
+       if (FAN_DATA_VALID(period))
+               rpm = FAN_PERIOD_TO_RPM(period);
+       else
+               rpm = 0;
+
+       return sprintf(buf, "%d\n", rpm);
+}
+
+static ssize_t set_fan_speed(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       int rpm = simple_strtol(buf, NULL, 10);
+       struct env *p = dev_get_drvdata(dev);
+       int period;
+       u8 val;
+
+       if (!rpm)
+               return -EINVAL;
+
+       period = FAN_RPM_TO_PERIOD(rpm);
+       val = period >> 8;
+       env_write(p, IREG_FAN0 + fan_nr, val);
+
+       return count;
+}
+
+static ssize_t show_fan_fault(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int fan_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       u8 val = env_read(p, IREG_FAN_STAT);
+       return sprintf(buf, "%d\n", (val & (1 << fan_nr)) ? 1 : 0);
+}
+
+#define fan(index)                                                     \
+static SENSOR_DEVICE_ATTR(fan##index##_speed, S_IRUGO | S_IWUSR,       \
+               show_fan_speed, set_fan_speed, index);                  \
+static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO,                 \
+               show_fan_fault, NULL, index)
+
+fan(0);
+fan(1);
+fan(2);
+fan(3);
+fan(4);
+
+static SENSOR_DEVICE_ATTR(psu_fan_fault, S_IRUGO, show_fan_fault, NULL, 6);
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int temp_nr = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       s8 val;
+
+       val = env_read(p, IREG_LCL_TEMP + temp_nr);
+       return sprintf(buf, "%d\n", ((int) val) - 64);
+}
+
+static SENSOR_DEVICE_ATTR(adt7462_local_temp, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(cpu0_temp, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(cpu1_temp, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(motherboard_temp, S_IRUGO, show_temp, NULL, 3);
+static SENSOR_DEVICE_ATTR(lm95221_local_temp, S_IRUGO, show_temp, NULL, 4);
+static SENSOR_DEVICE_ATTR(fire_temp, S_IRUGO, show_temp, NULL, 5);
+static SENSOR_DEVICE_ATTR(lsi1064_local_temp, S_IRUGO, show_temp, NULL, 6);
+static SENSOR_DEVICE_ATTR(front_panel_temp, S_IRUGO, show_temp, NULL, 7);
+static SENSOR_DEVICE_ATTR(psu_temp, S_IRUGO, show_temp, NULL, 13);
+
+static ssize_t show_stat_bit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       int index = to_sensor_dev_attr(attr)->index;
+       struct env *p = dev_get_drvdata(dev);
+       u8 val;
+
+       val = readb(p->regs + REG_STAT);
+       return sprintf(buf, "%d\n", (val & (1 << index)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(fan_failure, S_IRUGO, show_stat_bit, NULL, 0);
+static SENSOR_DEVICE_ATTR(env_bus_busy, S_IRUGO, show_stat_bit, NULL, 1);
+static SENSOR_DEVICE_ATTR(env_data_stale, S_IRUGO, show_stat_bit, NULL, 2);
+static SENSOR_DEVICE_ATTR(tpm_self_test_passed, S_IRUGO, show_stat_bit, NULL, 3);
+
+static ssize_t show_fwver(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct env *p = dev_get_drvdata(dev);
+       u8 val;
+
+       val = readb(p->regs + REG_STAT);
+       return sprintf(buf, "%d\n", val >> 4);
+}
+
+static SENSOR_DEVICE_ATTR(firmware_version, S_IRUGO, show_fwver, NULL, 0);
+
+static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "ultra45\n");
+}
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+
+static struct attribute *env_attributes[] = {
+       &sensor_dev_attr_fan0_speed.dev_attr.attr,
+       &sensor_dev_attr_fan0_fault.dev_attr.attr,
+       &sensor_dev_attr_fan1_speed.dev_attr.attr,
+       &sensor_dev_attr_fan1_fault.dev_attr.attr,
+       &sensor_dev_attr_fan2_speed.dev_attr.attr,
+       &sensor_dev_attr_fan2_fault.dev_attr.attr,
+       &sensor_dev_attr_fan3_speed.dev_attr.attr,
+       &sensor_dev_attr_fan3_fault.dev_attr.attr,
+       &sensor_dev_attr_fan4_speed.dev_attr.attr,
+       &sensor_dev_attr_fan4_fault.dev_attr.attr,
+       &sensor_dev_attr_psu_fan_fault.dev_attr.attr,
+       &sensor_dev_attr_adt7462_local_temp.dev_attr.attr,
+       &sensor_dev_attr_cpu0_temp.dev_attr.attr,
+       &sensor_dev_attr_cpu1_temp.dev_attr.attr,
+       &sensor_dev_attr_motherboard_temp.dev_attr.attr,
+       &sensor_dev_attr_lm95221_local_temp.dev_attr.attr,
+       &sensor_dev_attr_fire_temp.dev_attr.attr,
+       &sensor_dev_attr_lsi1064_local_temp.dev_attr.attr,
+       &sensor_dev_attr_front_panel_temp.dev_attr.attr,
+       &sensor_dev_attr_psu_temp.dev_attr.attr,
+       &sensor_dev_attr_fan_failure.dev_attr.attr,
+       &sensor_dev_attr_env_bus_busy.dev_attr.attr,
+       &sensor_dev_attr_env_data_stale.dev_attr.attr,
+       &sensor_dev_attr_tpm_self_test_passed.dev_attr.attr,
+       &sensor_dev_attr_firmware_version.dev_attr.attr,
+       &sensor_dev_attr_name.dev_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group env_group = {
+       .attrs = env_attributes,
+};
+
+static int __devinit env_probe(struct of_device *op,
+                              const struct of_device_id *match)
+{
+       struct env *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+
+       if (!p)
+               goto out;
+
+       spin_lock_init(&p->lock);
+
+       p->regs = of_ioremap(&op->resource[0], 0, REG_SIZE, "pic16f747");
+       if (!p->regs)
+               goto out_free;
+
+       err = sysfs_create_group(&op->dev.kobj, &env_group);
+       if (err)
+               goto out_iounmap;
+
+       p->hwmon_dev = hwmon_device_register(&op->dev);
+       if (IS_ERR(p->hwmon_dev)) {
+               err = PTR_ERR(p->hwmon_dev);
+               goto out_sysfs_remove_group;
+       }
+
+       dev_set_drvdata(&op->dev, p);
+       err = 0;
+
+out:
+       return err;
+
+out_sysfs_remove_group:
+       sysfs_remove_group(&op->dev.kobj, &env_group);
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit env_remove(struct of_device *op)
+{
+       struct env *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               sysfs_remove_group(&op->dev.kobj, &env_group);
+               hwmon_device_unregister(p->hwmon_dev);
+               of_iounmap(&op->resource[0], p->regs, REG_SIZE);
+               kfree(p);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id env_match[] = {
+       {
+               .name = "env-monitor",
+               .compatible = "SUNW,ebus-pic16f747-env",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, env_match);
+
+static struct of_platform_driver env_driver = {
+       .name           = "ultra45_env",
+       .match_table    = env_match,
+       .probe          = env_probe,
+       .remove         = __devexit_p(env_remove),
+};
+
+static int __init env_init(void)
+{
+       return of_register_driver(&env_driver, &of_bus_type);
+}
+
+static void __exit env_exit(void)
+{
+       of_unregister_driver(&env_driver);
+}
+
+module_init(env_init);
+module_exit(env_exit);
index d8765cc93d27d5daa1f343edea8bee7e75226117..c4f42311fdec9834a08ba2a331aa1c259bd77b1e 100644 (file)
@@ -249,7 +249,7 @@ static int bbc_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id bbc_beep_match[] = {
+static const struct of_device_id bbc_beep_match[] = {
        {
                .name = "beep",
                .compatible = "SUNW,bbc-beep",
@@ -328,7 +328,7 @@ static int grover_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id grover_beep_match[] = {
+static const struct of_device_id grover_beep_match[] = {
        {
                .name = "beep",
                .compatible = "SUNW,smbus-beep",
index 692a79ec2a22327e98c94ef4946fe2f69b6747da..5071af2c06040f3032d85f4f44be9be5f0202319 100644 (file)
@@ -87,7 +87,7 @@ static int __devexit sparc_i8042_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id sparc_i8042_match[] = {
+static const struct of_device_id sparc_i8042_match[] = {
        {
                .name = "8042",
        },
index 9ce3b3baf3a20b3cac63695bbe327048cab4b246..3ab6362f043c0e9db3d08f00b5f60db92da1f795 100644 (file)
@@ -335,11 +335,11 @@ static struct xenbus_driver xenkbd = {
 
 static int __init xenkbd_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        /* Nothing to do if running in dom0. */
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return -ENODEV;
 
        return xenbus_register_frontend(&xenkbd);
index 5b14262af0178797e174c7355680271d3ec04758..e3e40427e00e8f9081d1a5326785c021727cb158 100644 (file)
@@ -82,6 +82,14 @@ config LEDS_COBALT_RAQ
        help
          This option enables support for the Cobalt Raq series LEDs.
 
+config LEDS_SUNFIRE
+       tristate "LED support for SunFire servers."
+       depends on LEDS_CLASS && SPARC64
+       select LEDS_TRIGGERS
+       help
+         This option enables support for the Left, Middle, and Right
+         LEDs on the I/O and CPU boards of SunFire UltraSPARC servers.
+
 config LEDS_HP6XX
        tristate "LED Support for the HP Jornada 6xx"
        depends on LEDS_CLASS && SH_HP6XX
index 3a8e6a04363c501abc8217f894576ae519aea5d9..eb186c351a1c297d1c7bba0ffeb4f379f929afb7 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_LEDS_WRAP)                       += leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)               += leds-h1940.o
 obj-$(CONFIG_LEDS_COBALT_QUBE)         += leds-cobalt-qube.o
 obj-$(CONFIG_LEDS_COBALT_RAQ)          += leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_SUNFIRE)             += leds-sunfire.o
 obj-$(CONFIG_LEDS_PCA9532)             += leds-pca9532.o
 obj-$(CONFIG_LEDS_GPIO)                        += leds-gpio.o
 obj-$(CONFIG_LEDS_CM_X270)              += leds-cm-x270.o
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
new file mode 100644 (file)
index 0000000..6b008f0
--- /dev/null
@@ -0,0 +1,273 @@
+/* leds-sunfire.c: SUNW,Ultra-Enterprise LED driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+#define DRIVER_NAME    "leds-sunfire"
+#define PFX            DRIVER_NAME ": "
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun Fire LED driver");
+MODULE_LICENSE("GPL");
+
+struct sunfire_led {
+       struct led_classdev     led_cdev;
+       void __iomem            *reg;
+};
+#define        to_sunfire_led(d) container_of(d, struct sunfire_led, led_cdev)
+
+static void __clockboard_set(struct led_classdev *led_cdev,
+                            enum led_brightness led_val, u8 bit)
+{
+       struct sunfire_led *p = to_sunfire_led(led_cdev);
+       u8 reg = upa_readb(p->reg);
+
+       switch (bit) {
+       case CLOCK_CTRL_LLED:
+               if (led_val)
+                       reg &= ~bit;
+               else
+                       reg |= bit;
+               break;
+
+       default:
+               if (led_val)
+                       reg |= bit;
+               else
+                       reg &= ~bit;
+               break;
+       }
+       upa_writeb(reg, p->reg);
+}
+
+static void clockboard_left_set(struct led_classdev *led_cdev,
+                               enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_LLED);
+}
+
+static void clockboard_middle_set(struct led_classdev *led_cdev,
+                                 enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_MLED);
+}
+
+static void clockboard_right_set(struct led_classdev *led_cdev,
+                                enum led_brightness led_val)
+{
+       __clockboard_set(led_cdev, led_val, CLOCK_CTRL_RLED);
+}
+
+static void __fhc_set(struct led_classdev *led_cdev,
+                            enum led_brightness led_val, u32 bit)
+{
+       struct sunfire_led *p = to_sunfire_led(led_cdev);
+       u32 reg = upa_readl(p->reg);
+
+       switch (bit) {
+       case FHC_CONTROL_LLED:
+               if (led_val)
+                       reg &= ~bit;
+               else
+                       reg |= bit;
+               break;
+
+       default:
+               if (led_val)
+                       reg |= bit;
+               else
+                       reg &= ~bit;
+               break;
+       }
+       upa_writel(reg, p->reg);
+}
+
+static void fhc_left_set(struct led_classdev *led_cdev,
+                        enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_LLED);
+}
+
+static void fhc_middle_set(struct led_classdev *led_cdev,
+                          enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_MLED);
+}
+
+static void fhc_right_set(struct led_classdev *led_cdev,
+                         enum led_brightness led_val)
+{
+       __fhc_set(led_cdev, led_val, FHC_CONTROL_RLED);
+}
+
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+       const char      *name;
+       set_handler     handler;
+       const char      *default_trigger;
+};
+
+#define NUM_LEDS_PER_BOARD     3
+struct sunfire_drvdata {
+       struct sunfire_led      leds[NUM_LEDS_PER_BOARD];
+};
+
+static int __devinit sunfire_led_generic_probe(struct platform_device *pdev,
+                                              struct led_type *types)
+{
+       struct sunfire_drvdata *p;
+       int i, err = -EINVAL;
+
+       if (pdev->num_resources != 1) {
+               printk(KERN_ERR PFX "Wrong number of resources %d, should be 1\n",
+                      pdev->num_resources);
+               goto out;
+       }
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR PFX "Could not allocate struct sunfire_drvdata\n");
+               goto out;
+       }
+
+       for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+               struct led_classdev *lp = &p->leds[i].led_cdev;
+
+               p->leds[i].reg = (void __iomem *) pdev->resource[0].start;
+               lp->name = types[i].name;
+               lp->brightness = LED_FULL;
+               lp->brightness_set = types[i].handler;
+               lp->default_trigger = types[i].default_trigger;
+
+               err = led_classdev_register(&pdev->dev, lp);
+               if (err) {
+                       printk(KERN_ERR PFX "Could not register %s LED\n",
+                              lp->name);
+                       goto out_unregister_led_cdevs;
+               }
+       }
+
+       dev_set_drvdata(&pdev->dev, p);
+
+       err = 0;
+out:
+       return err;
+
+out_unregister_led_cdevs:
+       for (i--; i >= 0; i--)
+               led_classdev_unregister(&p->leds[i].led_cdev);
+       goto out;
+}
+
+static int __devexit sunfire_led_generic_remove(struct platform_device *pdev)
+{
+       struct sunfire_drvdata *p = dev_get_drvdata(&pdev->dev);
+       int i;
+
+       for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+               led_classdev_unregister(&p->leds[i].led_cdev);
+
+       kfree(p);
+
+       return 0;
+}
+
+static struct led_type clockboard_led_types[NUM_LEDS_PER_BOARD] = {
+       {
+               .name           = "clockboard-left",
+               .handler        = clockboard_left_set,
+       },
+       {
+               .name           = "clockboard-middle",
+               .handler        = clockboard_middle_set,
+       },
+       {
+               .name           = "clockboard-right",
+               .handler        = clockboard_right_set,
+               .default_trigger= "heartbeat",
+       },
+};
+
+static int __devinit sunfire_clockboard_led_probe(struct platform_device *pdev)
+{
+       return sunfire_led_generic_probe(pdev, clockboard_led_types);
+}
+
+static struct led_type fhc_led_types[NUM_LEDS_PER_BOARD] = {
+       {
+               .name           = "fhc-left",
+               .handler        = fhc_left_set,
+       },
+       {
+               .name           = "fhc-middle",
+               .handler        = fhc_middle_set,
+       },
+       {
+               .name           = "fhc-right",
+               .handler        = fhc_right_set,
+               .default_trigger= "heartbeat",
+       },
+};
+
+static int __devinit sunfire_fhc_led_probe(struct platform_device *pdev)
+{
+       return sunfire_led_generic_probe(pdev, fhc_led_types);
+}
+
+MODULE_ALIAS("platform:sunfire-clockboard-leds");
+MODULE_ALIAS("platform:sunfire-fhc-leds");
+
+static struct platform_driver sunfire_clockboard_led_driver = {
+       .probe          = sunfire_clockboard_led_probe,
+       .remove         = __devexit_p(sunfire_led_generic_remove),
+       .driver         = {
+               .name   = "sunfire-clockboard-leds",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static struct platform_driver sunfire_fhc_led_driver = {
+       .probe          = sunfire_fhc_led_probe,
+       .remove         = __devexit_p(sunfire_led_generic_remove),
+       .driver         = {
+               .name   = "sunfire-fhc-leds",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init sunfire_leds_init(void)
+{
+       int err = platform_driver_register(&sunfire_clockboard_led_driver);
+
+       if (err) {
+               printk(KERN_ERR PFX "Could not register clock board LED driver\n");
+               return err;
+       }
+
+       err = platform_driver_register(&sunfire_fhc_led_driver);
+       if (err) {
+               printk(KERN_ERR PFX "Could not register FHC LED driver\n");
+               platform_driver_unregister(&sunfire_clockboard_led_driver);
+       }
+
+       return err;
+}
+
+static void __exit sunfire_leds_exit(void)
+{
+       platform_driver_unregister(&sunfire_clockboard_led_driver);
+       platform_driver_unregister(&sunfire_fhc_led_driver);
+}
+
+module_init(sunfire_leds_init);
+module_exit(sunfire_leds_exit);
index c0b41e8bcd9d9311cef9976ca38e968746d72167..f2eeb38efa653387b42cb8bf9ccc0ba4e0f17969 100644 (file)
@@ -3,13 +3,14 @@
 #
 
 menuconfig MMC
-       tristate "MMC/SD card support"
+       tristate "MMC/SD/SDIO card support"
        depends on HAS_IOMEM
        help
-         MMC is the "multi-media card" bus protocol.
+         This selects MultiMediaCard, Secure Digital and Secure
+         Digital I/O support.
 
-         If you want MMC support, you should say Y here and also
-         to the specific driver for your MMC interface.
+         If you want MMC/SD/SDIO support, you should say Y here and
+         also to your specific host controller driver.
 
 config MMC_DEBUG
        bool "MMC debugging"
index dd0f398ee2f5398593b61100ad58850ca9e9d0b6..3f2a912659aff9a6ad596d7271ad60df2a332752 100644 (file)
@@ -2,7 +2,7 @@
 # MMC/SD card drivers
 #
 
-comment "MMC/SD Card Drivers"
+comment "MMC/SD/SDIO Card Drivers"
 
 config MMC_BLOCK
        tristate "MMC block device driver"
@@ -34,7 +34,6 @@ config MMC_BLOCK_BOUNCE
 
 config SDIO_UART
        tristate "SDIO UART/GPS class support"
-       depends on MMC
        help
          SDIO function driver for SDIO cards that implements the UART
          class, as well as the GPS class which appears like a UART.
index efacee0404a09c703b7f259fb0cb37401021b518..24c97d3d16bba43ab963d9b514ee27fbe938ddcc 100644 (file)
@@ -58,7 +58,6 @@ struct mmc_blk_data {
        struct mmc_queue queue;
 
        unsigned int    usage;
-       unsigned int    block_bits;
        unsigned int    read_only;
 };
 
@@ -216,8 +215,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
        struct mmc_blk_request brq;
-       int ret = 1, data_size, i;
-       struct scatterlist *sg;
+       int ret = 1;
 
        mmc_claim_host(card->host);
 
@@ -233,13 +231,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                if (!mmc_card_blockaddr(card))
                        brq.cmd.arg <<= 9;
                brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
-               brq.data.blksz = 1 << md->block_bits;
+               brq.data.blksz = 512;
                brq.stop.opcode = MMC_STOP_TRANSMISSION;
                brq.stop.arg = 0;
                brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-               brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
-               if (brq.data.blocks > card->host->max_blk_count)
-                       brq.data.blocks = card->host->max_blk_count;
+               brq.data.blocks = req->nr_sectors;
 
                if (brq.data.blocks > 1) {
                        /* SPI multiblock writes terminate using a special
@@ -271,24 +267,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
                mmc_queue_bounce_pre(mq);
 
-               /*
-                * Adjust the sg list so it is the same size as the
-                * request.
-                */
-               if (brq.data.blocks !=
-                   (req->nr_sectors >> (md->block_bits - 9))) {
-                       data_size = brq.data.blocks * brq.data.blksz;
-                       for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
-                               data_size -= sg->length;
-                               if (data_size <= 0) {
-                                       sg->length += data_size;
-                                       i++;
-                                       break;
-                               }
-                       }
-                       brq.data.sg_len = i;
-               }
-
                mmc_wait_for_req(card->host, &brq.mrq);
 
                mmc_queue_bounce_post(mq);
@@ -373,16 +351,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
        if (rq_data_dir(req) != READ) {
                if (mmc_card_sd(card)) {
                        u32 blocks;
-                       unsigned int bytes;
 
                        blocks = mmc_sd_num_wr_blocks(card);
                        if (blocks != (u32)-1) {
-                               if (card->csd.write_partial)
-                                       bytes = blocks << md->block_bits;
-                               else
-                                       bytes = blocks << 9;
                                spin_lock_irq(&md->lock);
-                               ret = __blk_end_request(req, 0, bytes);
+                               ret = __blk_end_request(req, 0, blocks << 9);
                                spin_unlock_irq(&md->lock);
                        }
                } else {
@@ -432,13 +405,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
        md->read_only = mmc_blk_readonly(card);
 
-       /*
-        * Both SD and MMC specifications state (although a bit
-        * unclearly in the MMC case) that a block size of 512
-        * bytes must always be supported by the card.
-        */
-       md->block_bits = 9;
-
        md->disk = alloc_disk(1 << MMC_SHIFT);
        if (md->disk == NULL) {
                ret = -ENOMEM;
@@ -476,7 +442,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 
        sprintf(md->disk->disk_name, "mmcblk%d", devidx);
 
-       blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
+       blk_queue_hardsect_size(md->queue.queue, 512);
 
        if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
                /*
@@ -514,7 +480,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 
        mmc_claim_host(card->host);
        cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = 1 << md->block_bits;
+       cmd.arg = 512;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
        err = mmc_wait_for_cmd(card->host, &cmd, 5);
        mmc_release_host(card->host);
index 3dee97e7d165f3e64f3898b1fb84c335cc4a1f08..406989e992bad75fe1f17e103f8aab87e9cccc11 100644 (file)
@@ -31,7 +31,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
        /*
         * We only like normal block requests.
         */
-       if (!blk_fs_request(req) && !blk_pc_request(req)) {
+       if (!blk_fs_request(req)) {
                blk_dump_rq_flags(req, "MMC bad request");
                return BLKPREP_KILL;
        }
@@ -131,6 +131,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        mq->req = NULL;
 
        blk_queue_prep_rq(mq->queue, mmc_prep_request);
+       blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
        if (host->max_hw_segs == 1) {
@@ -142,12 +143,19 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                        bouncesz = host->max_req_size;
                if (bouncesz > host->max_seg_size)
                        bouncesz = host->max_seg_size;
+               if (bouncesz > (host->max_blk_count * 512))
+                       bouncesz = host->max_blk_count * 512;
+
+               if (bouncesz > 512) {
+                       mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
+                       if (!mq->bounce_buf) {
+                               printk(KERN_WARNING "%s: unable to "
+                                       "allocate bounce buffer\n",
+                                       mmc_card_name(card));
+                       }
+               }
 
-               mq->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
-               if (!mq->bounce_buf) {
-                       printk(KERN_WARNING "%s: unable to allocate "
-                               "bounce buffer\n", mmc_card_name(card));
-               } else {
+               if (mq->bounce_buf) {
                        blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
                        blk_queue_max_sectors(mq->queue, bouncesz / 512);
                        blk_queue_max_phys_segments(mq->queue, bouncesz / 512);
@@ -175,7 +183,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
        if (!mq->bounce_buf) {
                blk_queue_bounce_limit(mq->queue, limit);
-               blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
+               blk_queue_max_sectors(mq->queue,
+                       min(host->max_blk_count, host->max_req_size / 512));
                blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
                blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
index 64b05c6270f2f3aef54d88e309f8772694c4347a..9c50e6f1c23649d75ba0a2522f5e52b04ff4740e 100644 (file)
@@ -248,8 +248,12 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
 
        sg_init_one(&sg, data_buf, len);
 
-       if (card)
-               mmc_set_data_timeout(&data, card);
+       /*
+        * The spec states that CSR and CID accesses have a timeout
+        * of 64 clock cycles.
+        */
+       data.timeout_ns = 0;
+       data.timeout_clks = 64;
 
        mmc_wait_for_req(host, &mrq);
 
index 4eab79e09cccacbab8b7ecf7d2ae780f9e5b9e05..fb99ccff908077f1a5bdf1cdc78099fd0ecd19c2 100644 (file)
@@ -164,6 +164,36 @@ static int sdio_enable_wide(struct mmc_card *card)
        return 0;
 }
 
+/*
+ * Test if the card supports high-speed mode and, if so, switch to it.
+ */
+static int sdio_enable_hs(struct mmc_card *card)
+{
+       int ret;
+       u8 speed;
+
+       if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
+               return 0;
+
+       if (!card->cccr.high_speed)
+               return 0;
+
+       ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
+       if (ret)
+               return ret;
+
+       speed |= SDIO_SPEED_EHS;
+
+       ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
+       if (ret)
+               return ret;
+
+       mmc_card_set_highspeed(card);
+       mmc_set_timing(card->host, MMC_TIMING_SD_HS);
+
+       return 0;
+}
+
 /*
  * Host is being removed. Free up the current card.
  */
@@ -333,10 +363,26 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                goto remove;
 
        /*
-        * No support for high-speed yet, so just set
-        * the card's maximum speed.
+        * Switch to high-speed (if supported).
         */
-       mmc_set_clock(host, card->cis.max_dtr);
+       err = sdio_enable_hs(card);
+       if (err)
+               goto remove;
+
+       /*
+        * Change to the card's maximum speed.
+        */
+       if (mmc_card_highspeed(card)) {
+               /*
+                * The SDIO specification doesn't mention how
+                * the CIS transfer speed register relates to
+                * high-speed, but it seems that 50 MHz is
+                * mandatory.
+                */
+               mmc_set_clock(host, 50000000);
+       } else {
+               mmc_set_clock(host, card->cis.max_dtr);
+       }
 
        /*
         * Switch to wider bus (if supported).
index c292e124107ac13ec36be751024ad3728cafaa40..bb192f90e8e9a0028770a04073aefed345d35f95 100644 (file)
@@ -5,6 +5,8 @@
  * Created:     June 18, 2007
  * Copyright:   MontaVista Software Inc.
  *
+ * Copyright 2008 Pierre Ossman
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or (at
@@ -107,11 +109,14 @@ static int sdio_irq_thread(void *_host)
 
                /*
                 * Give other threads a chance to run in the presence of
-                * errors.  FIXME: determine if due to card removal and
-                * possibly exit this thread if so.
+                * errors.
                 */
-               if (ret < 0)
-                       ssleep(1);
+               if (ret < 0) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (!kthread_should_stop())
+                               schedule_timeout(HZ);
+                       set_current_state(TASK_RUNNING);
+               }
 
                /*
                 * Adaptive polling frequency based on the assumption
@@ -154,7 +159,8 @@ static int sdio_card_irq_get(struct mmc_card *card)
        if (!host->sdio_irqs++) {
                atomic_set(&host->sdio_irq_thread_abort, 0);
                host->sdio_irq_thread =
-                       kthread_run(sdio_irq_thread, host, "ksdiorqd");
+                       kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
+                               mmc_hostname(host));
                if (IS_ERR(host->sdio_irq_thread)) {
                        int err = PTR_ERR(host->sdio_irq_thread);
                        host->sdio_irqs--;
index ea8d7a3490d9b7ee575f23587721337ac8cbbc4a..dfa585f7feafc26c383add66ff88d031f1cf2c1b 100644 (file)
@@ -2,7 +2,7 @@
 # MMC/SD host controller drivers
 #
 
-comment "MMC/SD Host Controller Drivers"
+comment "MMC/SD/SDIO Host Controller Drivers"
 
 config MMC_ARMMMCI
        tristate "ARM AMBA Multimedia Card Interface support"
@@ -114,6 +114,17 @@ config MMC_ATMELMCI
 
          If unsure, say N.
 
+config MMC_ATMELMCI_DMA
+       bool "Atmel MCI DMA support (EXPERIMENTAL)"
+       depends on MMC_ATMELMCI && DMA_ENGINE && EXPERIMENTAL
+       help
+         Say Y here to have the Atmel MCI driver use a DMA engine to
+         do data transfers and thus increase the throughput and
+         reduce the CPU utilization. Note that this is highly
+         experimental and may cause the driver to lock up.
+
+         If unsure, say N.
+
 config MMC_IMX
        tristate "Motorola i.MX Multimedia Card Interface support"
        depends on ARCH_IMX
@@ -141,21 +152,22 @@ config MMC_TIFM_SD
          module will be called tifm_sd.
 
 config MMC_SPI
-       tristate "MMC/SD over SPI"
-       depends on MMC && SPI_MASTER && !HIGHMEM && HAS_DMA
+       tristate "MMC/SD/SDIO over SPI"
+       depends on SPI_MASTER && !HIGHMEM && HAS_DMA
        select CRC7
        select CRC_ITU_T
        help
-         Some systems accss MMC/SD cards using a SPI controller instead of
-         using a "native" MMC/SD controller.  This has a disadvantage of
-         being relatively high overhead, but a compensating advantage of
-         working on many systems without dedicated MMC/SD controllers.
+         Some systems accss MMC/SD/SDIO cards using a SPI controller
+         instead of using a "native" MMC/SD/SDIO controller.  This has a
+         disadvantage of being relatively high overhead, but a compensating
+         advantage of working on many systems without dedicated MMC/SD/SDIO
+         controllers.
 
          If unsure, or if your system has no SPI master driver, say N.
 
 config MMC_S3C
        tristate "Samsung S3C SD/MMC Card Interface support"
-       depends on ARCH_S3C2410 && MMC
+       depends on ARCH_S3C2410
        help
          This selects a driver for the MCI interface found in
           Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@@ -166,7 +178,7 @@ config MMC_S3C
 
 config MMC_SDRICOH_CS
        tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && MMC && PCI && PCMCIA
+       depends on EXPERIMENTAL && PCI && PCMCIA
        help
          Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
          card whenever you insert a MMC or SD card into the card slot.
index 26bd80e650317397545b4c62d0393f7d429c6e36..b58364ed6bba7e487d4bf772e433b259a22933c5 100644 (file)
 #define MCI_SDCR               0x000c  /* SD Card / SDIO */
 # define MCI_SDCSEL_SLOT_A     (  0 <<  0)     /* Select SD slot A */
 # define MCI_SDCSEL_SLOT_B     (  1 <<  0)     /* Select SD slot A */
-# define MCI_SDCBUS_1BIT       (  0 <<  7)     /* 1-bit data bus */
-# define MCI_SDCBUS_4BIT       (  1 <<  7)     /* 4-bit data bus */
+# define MCI_SDCSEL_MASK       (  3 <<  0)
+# define MCI_SDCBUS_1BIT       (  0 <<  6)     /* 1-bit data bus */
+# define MCI_SDCBUS_4BIT       (  2 <<  6)     /* 4-bit data bus */
+# define MCI_SDCBUS_MASK       (  3 <<  6)
 #define MCI_ARGR               0x0010  /* Command Argument */
 #define MCI_CMDR               0x0014  /* Command */
 # define MCI_CMDR_CMDNB(x)     ((x) <<  0)     /* Command Opcode */
index 00008967ef7ae505568836510931eef134c59102..7a3f2436b0119f5a6ae49c65bf39bef0bc1fb286 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/clk.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
 #include "atmel-mci-regs.h"
 
 #define ATMCI_DATA_ERROR_FLAGS (MCI_DCRCE | MCI_DTOE | MCI_OVRE | MCI_UNRE)
+#define ATMCI_DMA_THRESHOLD    16
 
 enum {
        EVENT_CMD_COMPLETE = 0,
-       EVENT_DATA_ERROR,
-       EVENT_DATA_COMPLETE,
-       EVENT_STOP_SENT,
-       EVENT_STOP_COMPLETE,
        EVENT_XFER_COMPLETE,
+       EVENT_DATA_COMPLETE,
+       EVENT_DATA_ERROR,
+};
+
+enum atmel_mci_state {
+       STATE_IDLE = 0,
+       STATE_SENDING_CMD,
+       STATE_SENDING_DATA,
+       STATE_DATA_BUSY,
+       STATE_SENDING_STOP,
+       STATE_DATA_ERROR,
+};
+
+struct atmel_mci_dma {
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       struct dma_client               client;
+       struct dma_chan                 *chan;
+       struct dma_async_tx_descriptor  *data_desc;
+#endif
 };
 
+/**
+ * struct atmel_mci - MMC controller state shared between all slots
+ * @lock: Spinlock protecting the queue and associated data.
+ * @regs: Pointer to MMIO registers.
+ * @sg: Scatterlist entry currently being processed by PIO code, if any.
+ * @pio_offset: Offset into the current scatterlist entry.
+ * @cur_slot: The slot which is currently using the controller.
+ * @mrq: The request currently being processed on @cur_slot,
+ *     or NULL if the controller is idle.
+ * @cmd: The command currently being sent to the card, or NULL.
+ * @data: The data currently being transferred, or NULL if no data
+ *     transfer is in progress.
+ * @dma: DMA client state.
+ * @data_chan: DMA channel being used for the current data transfer.
+ * @cmd_status: Snapshot of SR taken upon completion of the current
+ *     command. Only valid when EVENT_CMD_COMPLETE is pending.
+ * @data_status: Snapshot of SR taken upon completion of the current
+ *     data transfer. Only valid when EVENT_DATA_COMPLETE or
+ *     EVENT_DATA_ERROR is pending.
+ * @stop_cmdr: Value to be loaded into CMDR when the stop command is
+ *     to be sent.
+ * @tasklet: Tasklet running the request state machine.
+ * @pending_events: Bitmask of events flagged by the interrupt handler
+ *     to be processed by the tasklet.
+ * @completed_events: Bitmask of events which the state machine has
+ *     processed.
+ * @state: Tasklet state.
+ * @queue: List of slots waiting for access to the controller.
+ * @need_clock_update: Update the clock rate before the next request.
+ * @need_reset: Reset controller before next request.
+ * @mode_reg: Value of the MR register.
+ * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
+ *     rate and timeout calculations.
+ * @mapbase: Physical address of the MMIO registers.
+ * @mck: The peripheral bus clock hooked up to the MMC controller.
+ * @pdev: Platform device associated with the MMC controller.
+ * @slot: Slots sharing this MMC controller.
+ *
+ * Locking
+ * =======
+ *
+ * @lock is a softirq-safe spinlock protecting @queue as well as
+ * @cur_slot, @mrq and @state. These must always be updated
+ * at the same time while holding @lock.
+ *
+ * @lock also protects mode_reg and need_clock_update since these are
+ * used to synchronize mode register updates with the queue
+ * processing.
+ *
+ * The @mrq field of struct atmel_mci_slot is also protected by @lock,
+ * and must always be written at the same time as the slot is added to
+ * @queue.
+ *
+ * @pending_events and @completed_events are accessed using atomic bit
+ * operations, so they don't need any locking.
+ *
+ * None of the fields touched by the interrupt handler need any
+ * locking. However, ordering is important: Before EVENT_DATA_ERROR or
+ * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
+ * interrupts must be disabled and @data_status updated with a
+ * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
+ * CMDRDY interupt must be disabled and @cmd_status updated with a
+ * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
+ * bytes_xfered field of @data must be written. This is ensured by
+ * using barriers.
+ */
 struct atmel_mci {
-       struct mmc_host         *mmc;
+       spinlock_t              lock;
        void __iomem            *regs;
 
        struct scatterlist      *sg;
        unsigned int            pio_offset;
 
+       struct atmel_mci_slot   *cur_slot;
        struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_data         *data;
 
+       struct atmel_mci_dma    dma;
+       struct dma_chan         *data_chan;
+
        u32                     cmd_status;
        u32                     data_status;
-       u32                     stop_status;
        u32                     stop_cmdr;
 
-       u32                     mode_reg;
-       u32                     sdc_reg;
-
        struct tasklet_struct   tasklet;
        unsigned long           pending_events;
        unsigned long           completed_events;
+       enum atmel_mci_state    state;
+       struct list_head        queue;
 
-       int                     present;
-       int                     detect_pin;
-       int                     wp_pin;
-
-       /* For detect pin debouncing */
-       struct timer_list       detect_timer;
-
+       bool                    need_clock_update;
+       bool                    need_reset;
+       u32                     mode_reg;
        unsigned long           bus_hz;
        unsigned long           mapbase;
        struct clk              *mck;
        struct platform_device  *pdev;
+
+       struct atmel_mci_slot   *slot[ATMEL_MCI_MAX_NR_SLOTS];
+};
+
+/**
+ * struct atmel_mci_slot - MMC slot state
+ * @mmc: The mmc_host representing this slot.
+ * @host: The MMC controller this slot is using.
+ * @sdc_reg: Value of SDCR to be written before using this slot.
+ * @mrq: mmc_request currently being processed or waiting to be
+ *     processed, or NULL when the slot is idle.
+ * @queue_node: List node for placing this node in the @queue list of
+ *     &struct atmel_mci.
+ * @clock: Clock rate configured by set_ios(). Protected by host->lock.
+ * @flags: Random state bits associated with the slot.
+ * @detect_pin: GPIO pin used for card detection, or negative if not
+ *     available.
+ * @wp_pin: GPIO pin used for card write protect sending, or negative
+ *     if not available.
+ * @detect_timer: Timer used for debouncing @detect_pin interrupts.
+ */
+struct atmel_mci_slot {
+       struct mmc_host         *mmc;
+       struct atmel_mci        *host;
+
+       u32                     sdc_reg;
+
+       struct mmc_request      *mrq;
+       struct list_head        queue_node;
+
+       unsigned int            clock;
+       unsigned long           flags;
+#define ATMCI_CARD_PRESENT     0
+#define ATMCI_CARD_NEED_INIT   1
+#define ATMCI_SHUTDOWN         2
+
+       int                     detect_pin;
+       int                     wp_pin;
+
+       struct timer_list       detect_timer;
 };
 
-#define atmci_is_completed(host, event)                                \
-       test_bit(event, &host->completed_events)
 #define atmci_test_and_clear_pending(host, event)              \
        test_and_clear_bit(event, &host->pending_events)
-#define atmci_test_and_set_completed(host, event)              \
-       test_and_set_bit(event, &host->completed_events)
 #define atmci_set_completed(host, event)                       \
        set_bit(event, &host->completed_events)
 #define atmci_set_pending(host, event)                         \
        set_bit(event, &host->pending_events)
-#define atmci_clear_pending(host, event)                       \
-       clear_bit(event, &host->pending_events)
 
 /*
  * The debugfs stuff below is mostly optimized away when
@@ -98,14 +214,15 @@ struct atmel_mci {
  */
 static int atmci_req_show(struct seq_file *s, void *v)
 {
-       struct atmel_mci        *host = s->private;
-       struct mmc_request      *mrq = host->mrq;
+       struct atmel_mci_slot   *slot = s->private;
+       struct mmc_request      *mrq;
        struct mmc_command      *cmd;
        struct mmc_command      *stop;
        struct mmc_data         *data;
 
        /* Make sure we get a consistent snapshot */
-       spin_lock_irq(&host->mmc->lock);
+       spin_lock_bh(&slot->host->lock);
+       mrq = slot->mrq;
 
        if (mrq) {
                cmd = mrq->cmd;
@@ -130,7 +247,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
                                stop->resp[2], stop->error);
        }
 
-       spin_unlock_irq(&host->mmc->lock);
+       spin_unlock_bh(&slot->host->lock);
 
        return 0;
 }
@@ -193,12 +310,16 @@ static int atmci_regs_show(struct seq_file *s, void *v)
        if (!buf)
                return -ENOMEM;
 
-       /* Grab a more or less consistent snapshot */
-       spin_lock_irq(&host->mmc->lock);
+       /*
+        * Grab a more or less consistent snapshot. Note that we're
+        * not disabling interrupts, so IMR and SR may not be
+        * consistent.
+        */
+       spin_lock_bh(&host->lock);
        clk_enable(host->mck);
        memcpy_fromio(buf, host->regs, MCI_REGS_SIZE);
        clk_disable(host->mck);
-       spin_unlock_irq(&host->mmc->lock);
+       spin_unlock_bh(&host->lock);
 
        seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
                        buf[MCI_MR / 4],
@@ -236,13 +357,13 @@ static const struct file_operations atmci_regs_fops = {
        .release        = single_release,
 };
 
-static void atmci_init_debugfs(struct atmel_mci *host)
+static void atmci_init_debugfs(struct atmel_mci_slot *slot)
 {
-       struct mmc_host *mmc;
-       struct dentry   *root;
-       struct dentry   *node;
+       struct mmc_host         *mmc = slot->mmc;
+       struct atmel_mci        *host = slot->host;
+       struct dentry           *root;
+       struct dentry           *node;
 
-       mmc = host->mmc;
        root = mmc->debugfs_root;
        if (!root)
                return;
@@ -254,7 +375,11 @@ static void atmci_init_debugfs(struct atmel_mci *host)
        if (!node)
                goto err;
 
-       node = debugfs_create_file("req", S_IRUSR, root, host, &atmci_req_fops);
+       node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+       if (!node)
+               goto err;
+
+       node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
        if (!node)
                goto err;
 
@@ -271,25 +396,7 @@ static void atmci_init_debugfs(struct atmel_mci *host)
        return;
 
 err:
-       dev_err(&host->pdev->dev,
-               "failed to initialize debugfs for controller\n");
-}
-
-static void atmci_enable(struct atmel_mci *host)
-{
-       clk_enable(host->mck);
-       mci_writel(host, CR, MCI_CR_MCIEN);
-       mci_writel(host, MR, host->mode_reg);
-       mci_writel(host, SDCR, host->sdc_reg);
-}
-
-static void atmci_disable(struct atmel_mci *host)
-{
-       mci_writel(host, CR, MCI_CR_SWRST);
-
-       /* Stall until write is complete, then disable the bus clock */
-       mci_readl(host, SR);
-       clk_disable(host->mck);
+       dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
 }
 
 static inline unsigned int ns_to_clocks(struct atmel_mci *host,
@@ -299,7 +406,7 @@ static inline unsigned int ns_to_clocks(struct atmel_mci *host,
 }
 
 static void atmci_set_timeout(struct atmel_mci *host,
-                             struct mmc_data *data)
+               struct atmel_mci_slot *slot, struct mmc_data *data)
 {
        static unsigned dtomul_to_shift[] = {
                0, 4, 7, 8, 10, 12, 16, 20
@@ -322,7 +429,7 @@ static void atmci_set_timeout(struct atmel_mci *host,
                dtocyc = 15;
        }
 
-       dev_vdbg(&host->mmc->class_dev, "setting timeout to %u cycles\n",
+       dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
                        dtocyc << dtomul_to_shift[dtomul]);
        mci_writel(host, DTOR, (MCI_DTOMUL(dtomul) | MCI_DTOCYC(dtocyc)));
 }
@@ -375,15 +482,12 @@ static u32 atmci_prepare_command(struct mmc_host *mmc,
 }
 
 static void atmci_start_command(struct atmel_mci *host,
-                               struct mmc_command *cmd,
-                               u32 cmd_flags)
+               struct mmc_command *cmd, u32 cmd_flags)
 {
-       /* Must read host->cmd after testing event flags */
-       smp_rmb();
        WARN_ON(host->cmd);
        host->cmd = cmd;
 
-       dev_vdbg(&host->mmc->class_dev,
+       dev_vdbg(&host->pdev->dev,
                        "start command: ARGR=0x%08x CMDR=0x%08x\n",
                        cmd->arg, cmd_flags);
 
@@ -391,34 +495,157 @@ static void atmci_start_command(struct atmel_mci *host,
        mci_writel(host, CMDR, cmd_flags);
 }
 
-static void send_stop_cmd(struct mmc_host *mmc, struct mmc_data *data)
+static void send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
 {
-       struct atmel_mci *host = mmc_priv(mmc);
-
        atmci_start_command(host, data->stop, host->stop_cmdr);
        mci_writel(host, IER, MCI_CMDRDY);
 }
 
-static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq)
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+static void atmci_dma_cleanup(struct atmel_mci *host)
 {
-       struct atmel_mci *host = mmc_priv(mmc);
+       struct mmc_data                 *data = host->data;
 
-       WARN_ON(host->cmd || host->data);
-       host->mrq = NULL;
+       dma_unmap_sg(&host->pdev->dev, data->sg, data->sg_len,
+                    ((data->flags & MMC_DATA_WRITE)
+                     ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
+}
+
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+       struct dma_chan *chan = host->data_chan;
+
+       if (chan) {
+               chan->device->device_terminate_all(chan);
+               atmci_dma_cleanup(host);
+       } else {
+               /* Data transfer was stopped by the interrupt handler */
+               atmci_set_pending(host, EVENT_XFER_COMPLETE);
+               mci_writel(host, IER, MCI_NOTBUSY);
+       }
+}
+
+/* This function is called by the DMA driver from tasklet context. */
+static void atmci_dma_complete(void *arg)
+{
+       struct atmel_mci        *host = arg;
+       struct mmc_data         *data = host->data;
+
+       dev_vdbg(&host->pdev->dev, "DMA complete\n");
+
+       atmci_dma_cleanup(host);
+
+       /*
+        * If the card was removed, data will be NULL. No point trying
+        * to send the stop command or waiting for NBUSY in this case.
+        */
+       if (data) {
+               atmci_set_pending(host, EVENT_XFER_COMPLETE);
+               tasklet_schedule(&host->tasklet);
+
+               /*
+                * Regardless of what the documentation says, we have
+                * to wait for NOTBUSY even after block read
+                * operations.
+                *
+                * When the DMA transfer is complete, the controller
+                * may still be reading the CRC from the card, i.e.
+                * the data transfer is still in progress and we
+                * haven't seen all the potential error bits yet.
+                *
+                * The interrupt handler will schedule a different
+                * tasklet to finish things up when the data transfer
+                * is completely done.
+                *
+                * We may not complete the mmc request here anyway
+                * because the mmc layer may call back and cause us to
+                * violate the "don't submit new operations from the
+                * completion callback" rule of the dma engine
+                * framework.
+                */
+               mci_writel(host, IER, MCI_NOTBUSY);
+       }
+}
+
+static int
+atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+       struct dma_chan                 *chan;
+       struct dma_async_tx_descriptor  *desc;
+       struct scatterlist              *sg;
+       unsigned int                    i;
+       enum dma_data_direction         direction;
+
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-word-aligned buffers or lengths. Also, we don't bother
+        * with all the DMA setup overhead for short transfers.
+        */
+       if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
+               return -EINVAL;
+       if (data->blksz & 3)
+               return -EINVAL;
+
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               if (sg->offset & 3 || sg->length & 3)
+                       return -EINVAL;
+       }
+
+       /* If we don't have a channel, we can't do DMA */
+       chan = host->dma.chan;
+       if (chan) {
+               dma_chan_get(chan);
+               host->data_chan = chan;
+       }
+
+       if (!chan)
+               return -ENODEV;
+
+       if (data->flags & MMC_DATA_READ)
+               direction = DMA_FROM_DEVICE;
+       else
+               direction = DMA_TO_DEVICE;
+
+       desc = chan->device->device_prep_slave_sg(chan,
+                       data->sg, data->sg_len, direction,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!desc)
+               return -ENOMEM;
 
-       atmci_disable(host);
+       host->dma.data_desc = desc;
+       desc->callback = atmci_dma_complete;
+       desc->callback_param = host;
+       desc->tx_submit(desc);
 
-       mmc_request_done(mmc, mrq);
+       /* Go! */
+       chan->device->device_issue_pending(chan);
+
+       return 0;
+}
+
+#else /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
+{
+       return -ENOSYS;
 }
 
+static void atmci_stop_dma(struct atmel_mci *host)
+{
+       /* Data transfer was stopped by the interrupt handler */
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
+       mci_writel(host, IER, MCI_NOTBUSY);
+}
+
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
 /*
  * Returns a mask of interrupt flags to be enabled after the whole
  * request has been prepared.
  */
-static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
+static u32 atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-       u32                     iflags;
+       u32 iflags;
 
        data->error = -EINPROGRESS;
 
@@ -426,77 +653,89 @@ static u32 atmci_submit_data(struct mmc_host *mmc, struct mmc_data *data)
        host->sg = NULL;
        host->data = data;
 
-       dev_vdbg(&mmc->class_dev, "BLKR=0x%08x\n",
-                       MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
-
        iflags = ATMCI_DATA_ERROR_FLAGS;
-       host->sg = data->sg;
-       host->pio_offset = 0;
-       if (data->flags & MMC_DATA_READ)
-               iflags |= MCI_RXRDY;
-       else
-               iflags |= MCI_TXRDY;
+       if (atmci_submit_data_dma(host, data)) {
+               host->data_chan = NULL;
+
+               /*
+                * Errata: MMC data write operation with less than 12
+                * bytes is impossible.
+                *
+                * Errata: MCI Transmit Data Register (TDR) FIFO
+                * corruption when length is not multiple of 4.
+                */
+               if (data->blocks * data->blksz < 12
+                               || (data->blocks * data->blksz) & 3)
+                       host->need_reset = true;
+
+               host->sg = data->sg;
+               host->pio_offset = 0;
+               if (data->flags & MMC_DATA_READ)
+                       iflags |= MCI_RXRDY;
+               else
+                       iflags |= MCI_TXRDY;
+       }
 
        return iflags;
 }
 
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+static void atmci_start_request(struct atmel_mci *host,
+               struct atmel_mci_slot *slot)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-       struct mmc_data         *data;
+       struct mmc_request      *mrq;
        struct mmc_command      *cmd;
+       struct mmc_data         *data;
        u32                     iflags;
-       u32                     cmdflags = 0;
-
-       iflags = mci_readl(host, IMR);
-       if (iflags)
-               dev_warn(&mmc->class_dev, "WARNING: IMR=0x%08x\n",
-                               mci_readl(host, IMR));
-
-       WARN_ON(host->mrq != NULL);
-
-       /*
-        * We may "know" the card is gone even though there's still an
-        * electrical connection. If so, we really need to communicate
-        * this to the MMC core since there won't be any more
-        * interrupts as the card is completely removed. Otherwise,
-        * the MMC core might believe the card is still there even
-        * though the card was just removed very slowly.
-        */
-       if (!host->present) {
-               mrq->cmd->error = -ENOMEDIUM;
-               mmc_request_done(mmc, mrq);
-               return;
-       }
+       u32                     cmdflags;
 
+       mrq = slot->mrq;
+       host->cur_slot = slot;
        host->mrq = mrq;
+
        host->pending_events = 0;
        host->completed_events = 0;
+       host->data_status = 0;
 
-       atmci_enable(host);
+       if (host->need_reset) {
+               mci_writel(host, CR, MCI_CR_SWRST);
+               mci_writel(host, CR, MCI_CR_MCIEN);
+               mci_writel(host, MR, host->mode_reg);
+               host->need_reset = false;
+       }
+       mci_writel(host, SDCR, slot->sdc_reg);
 
-       /* We don't support multiple blocks of weird lengths. */
+       iflags = mci_readl(host, IMR);
+       if (iflags)
+               dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
+                               iflags);
+
+       if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
+               /* Send init sequence (74 clock cycles) */
+               mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
+               while (!(mci_readl(host, SR) & MCI_CMDRDY))
+                       cpu_relax();
+       }
        data = mrq->data;
        if (data) {
-               if (data->blocks > 1 && data->blksz & 3)
-                       goto fail;
-               atmci_set_timeout(host, data);
+               atmci_set_timeout(host, slot, data);
 
                /* Must set block count/size before sending command */
                mci_writel(host, BLKR, MCI_BCNT(data->blocks)
                                | MCI_BLKLEN(data->blksz));
+               dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
+                       MCI_BCNT(data->blocks) | MCI_BLKLEN(data->blksz));
        }
 
        iflags = MCI_CMDRDY;
        cmd = mrq->cmd;
-       cmdflags = atmci_prepare_command(mmc, cmd);
+       cmdflags = atmci_prepare_command(slot->mmc, cmd);
        atmci_start_command(host, cmd, cmdflags);
 
        if (data)
-               iflags |= atmci_submit_data(mmc, data);
+               iflags |= atmci_submit_data(host, data);
 
        if (mrq->stop) {
-               host->stop_cmdr = atmci_prepare_command(mmc, mrq->stop);
+               host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
                host->stop_cmdr |= MCI_CMDR_STOP_XFER;
                if (!(data->flags & MMC_DATA_WRITE))
                        host->stop_cmdr |= MCI_CMDR_TRDIR_READ;
@@ -513,59 +752,156 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
         * prepared yet.)
         */
        mci_writel(host, IER, iflags);
+}
 
-       return;
+static void atmci_queue_request(struct atmel_mci *host,
+               struct atmel_mci_slot *slot, struct mmc_request *mrq)
+{
+       dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
+                       host->state);
+
+       spin_lock_bh(&host->lock);
+       slot->mrq = mrq;
+       if (host->state == STATE_IDLE) {
+               host->state = STATE_SENDING_CMD;
+               atmci_start_request(host, slot);
+       } else {
+               list_add_tail(&slot->queue_node, &host->queue);
+       }
+       spin_unlock_bh(&host->lock);
+}
 
-fail:
-       atmci_disable(host);
-       host->mrq = NULL;
-       mrq->cmd->error = -EINVAL;
-       mmc_request_done(mmc, mrq);
+static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+       struct mmc_data         *data;
+
+       WARN_ON(slot->mrq);
+
+       /*
+        * We may "know" the card is gone even though there's still an
+        * electrical connection. If so, we really need to communicate
+        * this to the MMC core since there won't be any more
+        * interrupts as the card is completely removed. Otherwise,
+        * the MMC core might believe the card is still there even
+        * though the card was just removed very slowly.
+        */
+       if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
+               mrq->cmd->error = -ENOMEDIUM;
+               mmc_request_done(mmc, mrq);
+               return;
+       }
+
+       /* We don't support multiple blocks of weird lengths. */
+       data = mrq->data;
+       if (data && data->blocks > 1 && data->blksz & 3) {
+               mrq->cmd->error = -EINVAL;
+               mmc_request_done(mmc, mrq);
+       }
+
+       atmci_queue_request(host, slot, mrq);
 }
 
 static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+       struct atmel_mci        *host = slot->host;
+       unsigned int            i;
+
+       slot->sdc_reg &= ~MCI_SDCBUS_MASK;
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_1:
+               slot->sdc_reg |= MCI_SDCBUS_1BIT;
+               break;
+       case MMC_BUS_WIDTH_4:
+               slot->sdc_reg = MCI_SDCBUS_4BIT;
+               break;
+       }
 
        if (ios->clock) {
+               unsigned int clock_min = ~0U;
                u32 clkdiv;
 
-               /* Set clock rate */
-               clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1;
+               spin_lock_bh(&host->lock);
+               if (!host->mode_reg) {
+                       clk_enable(host->mck);
+                       mci_writel(host, CR, MCI_CR_SWRST);
+                       mci_writel(host, CR, MCI_CR_MCIEN);
+               }
+
+               /*
+                * Use mirror of ios->clock to prevent race with mmc
+                * core ios update when finding the minimum.
+                */
+               slot->clock = ios->clock;
+               for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+                       if (host->slot[i] && host->slot[i]->clock
+                                       && host->slot[i]->clock < clock_min)
+                               clock_min = host->slot[i]->clock;
+               }
+
+               /* Calculate clock divider */
+               clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
                if (clkdiv > 255) {
                        dev_warn(&mmc->class_dev,
                                "clock %u too slow; using %lu\n",
-                               ios->clock, host->bus_hz / (2 * 256));
+                               clock_min, host->bus_hz / (2 * 256));
                        clkdiv = 255;
                }
 
+               /*
+                * WRPROOF and RDPROOF prevent overruns/underruns by
+                * stopping the clock when the FIFO is full/empty.
+                * This state is not expected to last for long.
+                */
                host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF
                                        | MCI_MR_RDPROOF;
-       }
 
-       switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               host->sdc_reg = 0;
-               break;
-       case MMC_BUS_WIDTH_4:
-               host->sdc_reg = MCI_SDCBUS_4BIT;
-               break;
+               if (list_empty(&host->queue))
+                       mci_writel(host, MR, host->mode_reg);
+               else
+                       host->need_clock_update = true;
+
+               spin_unlock_bh(&host->lock);
+       } else {
+               bool any_slot_active = false;
+
+               spin_lock_bh(&host->lock);
+               slot->clock = 0;
+               for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+                       if (host->slot[i] && host->slot[i]->clock) {
+                               any_slot_active = true;
+                               break;
+                       }
+               }
+               if (!any_slot_active) {
+                       mci_writel(host, CR, MCI_CR_MCIDIS);
+                       if (host->mode_reg) {
+                               mci_readl(host, MR);
+                               clk_disable(host->mck);
+                       }
+                       host->mode_reg = 0;
+               }
+               spin_unlock_bh(&host->lock);
        }
 
        switch (ios->power_mode) {
-       case MMC_POWER_ON:
-               /* Send init sequence (74 clock cycles) */
-               atmci_enable(host);
-               mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT);
-               while (!(mci_readl(host, SR) & MCI_CMDRDY))
-                       cpu_relax();
-               atmci_disable(host);
+       case MMC_POWER_UP:
+               set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
                break;
        default:
                /*
                 * TODO: None of the currently available AVR32-based
                 * boards allow MMC power to be turned off. Implement
                 * power control when this can be tested properly.
+                *
+                * We also need to hook this into the clock management
+                * somehow so that newly inserted cards aren't
+                * subjected to a fast clock before we have a chance
+                * to figure out what the maximum rate is. Currently,
+                * there's no way to avoid this, and there never will
+                * be for boards that don't support power control.
                 */
                break;
        }
@@ -573,31 +909,82 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
 static int atmci_get_ro(struct mmc_host *mmc)
 {
-       int                     read_only = 0;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       int                     read_only = -ENOSYS;
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
 
-       if (gpio_is_valid(host->wp_pin)) {
-               read_only = gpio_get_value(host->wp_pin);
+       if (gpio_is_valid(slot->wp_pin)) {
+               read_only = gpio_get_value(slot->wp_pin);
                dev_dbg(&mmc->class_dev, "card is %s\n",
                                read_only ? "read-only" : "read-write");
-       } else {
-               dev_dbg(&mmc->class_dev,
-                       "no pin for checking read-only switch."
-                       " Assuming write-enable.\n");
        }
 
        return read_only;
 }
 
-static struct mmc_host_ops atmci_ops = {
+static int atmci_get_cd(struct mmc_host *mmc)
+{
+       int                     present = -ENOSYS;
+       struct atmel_mci_slot   *slot = mmc_priv(mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               present = !gpio_get_value(slot->detect_pin);
+               dev_dbg(&mmc->class_dev, "card is %spresent\n",
+                               present ? "" : "not ");
+       }
+
+       return present;
+}
+
+static const struct mmc_host_ops atmci_ops = {
        .request        = atmci_request,
        .set_ios        = atmci_set_ios,
        .get_ro         = atmci_get_ro,
+       .get_cd         = atmci_get_cd,
 };
 
+/* Called with host->lock held */
+static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
+       __releases(&host->lock)
+       __acquires(&host->lock)
+{
+       struct atmel_mci_slot   *slot = NULL;
+       struct mmc_host         *prev_mmc = host->cur_slot->mmc;
+
+       WARN_ON(host->cmd || host->data);
+
+       /*
+        * Update the MMC clock rate if necessary. This may be
+        * necessary if set_ios() is called when a different slot is
+        * busy transfering data.
+        */
+       if (host->need_clock_update)
+               mci_writel(host, MR, host->mode_reg);
+
+       host->cur_slot->mrq = NULL;
+       host->mrq = NULL;
+       if (!list_empty(&host->queue)) {
+               slot = list_entry(host->queue.next,
+                               struct atmel_mci_slot, queue_node);
+               list_del(&slot->queue_node);
+               dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
+                               mmc_hostname(slot->mmc));
+               host->state = STATE_SENDING_CMD;
+               atmci_start_request(host, slot);
+       } else {
+               dev_vdbg(&host->pdev->dev, "list empty\n");
+               host->state = STATE_IDLE;
+       }
+
+       spin_unlock(&host->lock);
+       mmc_request_done(prev_mmc, mrq);
+       spin_lock(&host->lock);
+}
+
 static void atmci_command_complete(struct atmel_mci *host,
-                       struct mmc_command *cmd, u32 status)
+                       struct mmc_command *cmd)
 {
+       u32             status = host->cmd_status;
+
        /* Read the response from the card (up to 16 bytes) */
        cmd->resp[0] = mci_readl(host, RSPR);
        cmd->resp[1] = mci_readl(host, RSPR);
@@ -614,11 +1001,12 @@ static void atmci_command_complete(struct atmel_mci *host,
                cmd->error = 0;
 
        if (cmd->error) {
-               dev_dbg(&host->mmc->class_dev,
+               dev_dbg(&host->pdev->dev,
                        "command error: status=0x%08x\n", status);
 
                if (cmd->data) {
                        host->data = NULL;
+                       atmci_stop_dma(host);
                        mci_writel(host, IDR, MCI_NOTBUSY
                                        | MCI_TXRDY | MCI_RXRDY
                                        | ATMCI_DATA_ERROR_FLAGS);
@@ -628,146 +1016,222 @@ static void atmci_command_complete(struct atmel_mci *host,
 
 static void atmci_detect_change(unsigned long data)
 {
-       struct atmel_mci *host = (struct atmel_mci *)data;
-       struct mmc_request *mrq = host->mrq;
-       int present;
+       struct atmel_mci_slot   *slot = (struct atmel_mci_slot *)data;
+       bool                    present;
+       bool                    present_old;
 
        /*
-        * atmci_remove() sets detect_pin to -1 before freeing the
-        * interrupt. We must not re-enable the interrupt if it has
-        * been freed.
+        * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
+        * freeing the interrupt. We must not re-enable the interrupt
+        * if it has been freed, and if we're shutting down, it
+        * doesn't really matter whether the card is present or not.
         */
        smp_rmb();
-       if (!gpio_is_valid(host->detect_pin))
+       if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
                return;
 
-       enable_irq(gpio_to_irq(host->detect_pin));
-       present = !gpio_get_value(host->detect_pin);
+       enable_irq(gpio_to_irq(slot->detect_pin));
+       present = !gpio_get_value(slot->detect_pin);
+       present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
+
+       dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
+                       present, present_old);
 
-       dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
-                       present, host->present);
+       if (present != present_old) {
+               struct atmel_mci        *host = slot->host;
+               struct mmc_request      *mrq;
 
-       if (present != host->present) {
-               dev_dbg(&host->mmc->class_dev, "card %s\n",
+               dev_dbg(&slot->mmc->class_dev, "card %s\n",
                        present ? "inserted" : "removed");
-               host->present = present;
 
-               /* Reset controller if card is gone */
-               if (!present) {
-                       mci_writel(host, CR, MCI_CR_SWRST);
-                       mci_writel(host, IDR, ~0UL);
-                       mci_writel(host, CR, MCI_CR_MCIEN);
-               }
+               spin_lock(&host->lock);
+
+               if (!present)
+                       clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+               else
+                       set_bit(ATMCI_CARD_PRESENT, &slot->flags);
 
                /* Clean up queue if present */
+               mrq = slot->mrq;
                if (mrq) {
-                       /*
-                        * Reset controller to terminate any ongoing
-                        * commands or data transfers.
-                        */
-                       mci_writel(host, CR, MCI_CR_SWRST);
+                       if (mrq == host->mrq) {
+                               /*
+                                * Reset controller to terminate any ongoing
+                                * commands or data transfers.
+                                */
+                               mci_writel(host, CR, MCI_CR_SWRST);
+                               mci_writel(host, CR, MCI_CR_MCIEN);
+                               mci_writel(host, MR, host->mode_reg);
 
-                       if (!atmci_is_completed(host, EVENT_CMD_COMPLETE))
-                               mrq->cmd->error = -ENOMEDIUM;
-
-                       if (mrq->data && !atmci_is_completed(host,
-                                               EVENT_DATA_COMPLETE)) {
                                host->data = NULL;
-                               mrq->data->error = -ENOMEDIUM;
+                               host->cmd = NULL;
+
+                               switch (host->state) {
+                               case STATE_IDLE:
+                                       break;
+                               case STATE_SENDING_CMD:
+                                       mrq->cmd->error = -ENOMEDIUM;
+                                       if (!mrq->data)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_DATA:
+                                       mrq->data->error = -ENOMEDIUM;
+                                       atmci_stop_dma(host);
+                                       break;
+                               case STATE_DATA_BUSY:
+                               case STATE_DATA_ERROR:
+                                       if (mrq->data->error == -EINPROGRESS)
+                                               mrq->data->error = -ENOMEDIUM;
+                                       if (!mrq->stop)
+                                               break;
+                                       /* fall through */
+                               case STATE_SENDING_STOP:
+                                       mrq->stop->error = -ENOMEDIUM;
+                                       break;
+                               }
+
+                               atmci_request_end(host, mrq);
+                       } else {
+                               list_del(&slot->queue_node);
+                               mrq->cmd->error = -ENOMEDIUM;
+                               if (mrq->data)
+                                       mrq->data->error = -ENOMEDIUM;
+                               if (mrq->stop)
+                                       mrq->stop->error = -ENOMEDIUM;
+
+                               spin_unlock(&host->lock);
+                               mmc_request_done(slot->mmc, mrq);
+                               spin_lock(&host->lock);
                        }
-                       if (mrq->stop && !atmci_is_completed(host,
-                                               EVENT_STOP_COMPLETE))
-                               mrq->stop->error = -ENOMEDIUM;
-
-                       host->cmd = NULL;
-                       atmci_request_end(host->mmc, mrq);
                }
+               spin_unlock(&host->lock);
 
-               mmc_detect_change(host->mmc, 0);
+               mmc_detect_change(slot->mmc, 0);
        }
 }
 
 static void atmci_tasklet_func(unsigned long priv)
 {
-       struct mmc_host         *mmc = (struct mmc_host *)priv;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci        *host = (struct atmel_mci *)priv;
        struct mmc_request      *mrq = host->mrq;
        struct mmc_data         *data = host->data;
+       struct mmc_command      *cmd = host->cmd;
+       enum atmel_mci_state    state = host->state;
+       enum atmel_mci_state    prev_state;
+       u32                     status;
+
+       spin_lock(&host->lock);
 
-       dev_vdbg(&mmc->class_dev,
-               "tasklet: pending/completed/mask %lx/%lx/%x\n",
-               host->pending_events, host->completed_events,
+       state = host->state;
+
+       dev_vdbg(&host->pdev->dev,
+               "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
+               state, host->pending_events, host->completed_events,
                mci_readl(host, IMR));
 
-       if (atmci_test_and_clear_pending(host, EVENT_CMD_COMPLETE)) {
-               /*
-                * host->cmd must be set to NULL before the interrupt
-                * handler sees EVENT_CMD_COMPLETE
-                */
-               host->cmd = NULL;
-               smp_wmb();
-               atmci_set_completed(host, EVENT_CMD_COMPLETE);
-               atmci_command_complete(host, mrq->cmd, host->cmd_status);
-
-               if (!mrq->cmd->error && mrq->stop
-                               && atmci_is_completed(host, EVENT_XFER_COMPLETE)
-                               && !atmci_test_and_set_completed(host,
-                                       EVENT_STOP_SENT))
-                       send_stop_cmd(host->mmc, mrq->data);
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_STOP_COMPLETE)) {
-               /*
-                * host->cmd must be set to NULL before the interrupt
-                * handler sees EVENT_STOP_COMPLETE
-                */
-               host->cmd = NULL;
-               smp_wmb();
-               atmci_set_completed(host, EVENT_STOP_COMPLETE);
-               atmci_command_complete(host, mrq->stop, host->stop_status);
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_DATA_ERROR)) {
-               u32 status = host->data_status;
+       do {
+               prev_state = state;
 
-               dev_vdbg(&mmc->class_dev, "data error: status=%08x\n", status);
+               switch (state) {
+               case STATE_IDLE:
+                       break;
 
-               atmci_set_completed(host, EVENT_DATA_ERROR);
-               atmci_set_completed(host, EVENT_DATA_COMPLETE);
+               case STATE_SENDING_CMD:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
 
-               if (status & MCI_DTOE) {
-                       dev_dbg(&mmc->class_dev,
-                                       "data timeout error\n");
-                       data->error = -ETIMEDOUT;
-               } else if (status & MCI_DCRCE) {
-                       dev_dbg(&mmc->class_dev, "data CRC error\n");
-                       data->error = -EILSEQ;
-               } else {
-                       dev_dbg(&mmc->class_dev,
-                                       "data FIFO error (status=%08x)\n",
-                                       status);
-                       data->error = -EIO;
-               }
+                       host->cmd = NULL;
+                       atmci_set_completed(host, EVENT_CMD_COMPLETE);
+                       atmci_command_complete(host, mrq->cmd);
+                       if (!mrq->data || cmd->error) {
+                               atmci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_DATA;
+                       /* fall through */
+
+               case STATE_SENDING_DATA:
+                       if (atmci_test_and_clear_pending(host,
+                                               EVENT_DATA_ERROR)) {
+                               atmci_stop_dma(host);
+                               if (data->stop)
+                                       send_stop_cmd(host, data);
+                               state = STATE_DATA_ERROR;
+                               break;
+                       }
 
-               if (host->present && data->stop
-                               && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                               && !atmci_test_and_set_completed(
-                                       host, EVENT_STOP_SENT))
-                       send_stop_cmd(host->mmc, data);
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
 
-               host->data = NULL;
-       }
-       if (atmci_test_and_clear_pending(host, EVENT_DATA_COMPLETE)) {
-               atmci_set_completed(host, EVENT_DATA_COMPLETE);
+                       atmci_set_completed(host, EVENT_XFER_COMPLETE);
+                       prev_state = state = STATE_DATA_BUSY;
+                       /* fall through */
+
+               case STATE_DATA_BUSY:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_DATA_COMPLETE))
+                               break;
 
-               if (!atmci_is_completed(host, EVENT_DATA_ERROR)) {
-                       data->bytes_xfered = data->blocks * data->blksz;
-                       data->error = 0;
+                       host->data = NULL;
+                       atmci_set_completed(host, EVENT_DATA_COMPLETE);
+                       status = host->data_status;
+                       if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
+                               if (status & MCI_DTOE) {
+                                       dev_dbg(&host->pdev->dev,
+                                                       "data timeout error\n");
+                                       data->error = -ETIMEDOUT;
+                               } else if (status & MCI_DCRCE) {
+                                       dev_dbg(&host->pdev->dev,
+                                                       "data CRC error\n");
+                                       data->error = -EILSEQ;
+                               } else {
+                                       dev_dbg(&host->pdev->dev,
+                                               "data FIFO error (status=%08x)\n",
+                                               status);
+                                       data->error = -EIO;
+                               }
+                       } else {
+                               data->bytes_xfered = data->blocks * data->blksz;
+                               data->error = 0;
+                       }
+
+                       if (!data->stop) {
+                               atmci_request_end(host, host->mrq);
+                               goto unlock;
+                       }
+
+                       prev_state = state = STATE_SENDING_STOP;
+                       if (!data->error)
+                               send_stop_cmd(host, data);
+                       /* fall through */
+
+               case STATE_SENDING_STOP:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_CMD_COMPLETE))
+                               break;
+
+                       host->cmd = NULL;
+                       atmci_command_complete(host, mrq->stop);
+                       atmci_request_end(host, host->mrq);
+                       goto unlock;
+
+               case STATE_DATA_ERROR:
+                       if (!atmci_test_and_clear_pending(host,
+                                               EVENT_XFER_COMPLETE))
+                               break;
+
+                       state = STATE_DATA_BUSY;
+                       break;
                }
+       } while (state != prev_state);
 
-               host->data = NULL;
-       }
+       host->state = state;
 
-       if (host->mrq && !host->cmd && !host->data)
-               atmci_request_end(mmc, host->mrq);
+unlock:
+       spin_unlock(&host->lock);
 }
 
 static void atmci_read_data_pio(struct atmel_mci *host)
@@ -789,6 +1253,7 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                        nbytes += 4;
 
                        if (offset == sg->length) {
+                               flush_dcache_page(sg_page(sg));
                                host->sg = sg = sg_next(sg);
                                if (!sg)
                                        goto done;
@@ -817,9 +1282,11 @@ static void atmci_read_data_pio(struct atmel_mci *host)
                        mci_writel(host, IDR, (MCI_NOTBUSY | MCI_RXRDY
                                                | ATMCI_DATA_ERROR_FLAGS));
                        host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
-                       break;
+                       return;
                }
        } while (status & MCI_RXRDY);
 
@@ -832,10 +1299,8 @@ done:
        mci_writel(host, IDR, MCI_RXRDY);
        mci_writel(host, IER, MCI_NOTBUSY);
        data->bytes_xfered += nbytes;
-       atmci_set_completed(host, EVENT_XFER_COMPLETE);
-       if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                       && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-               send_stop_cmd(host->mmc, data);
+       smp_wmb();
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
 static void atmci_write_data_pio(struct atmel_mci *host)
@@ -888,9 +1353,11 @@ static void atmci_write_data_pio(struct atmel_mci *host)
                        mci_writel(host, IDR, (MCI_NOTBUSY | MCI_TXRDY
                                                | ATMCI_DATA_ERROR_FLAGS));
                        host->data_status = status;
+                       data->bytes_xfered += nbytes;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
-                       break;
+                       return;
                }
        } while (status & MCI_TXRDY);
 
@@ -903,38 +1370,26 @@ done:
        mci_writel(host, IDR, MCI_TXRDY);
        mci_writel(host, IER, MCI_NOTBUSY);
        data->bytes_xfered += nbytes;
-       atmci_set_completed(host, EVENT_XFER_COMPLETE);
-       if (data->stop && atmci_is_completed(host, EVENT_CMD_COMPLETE)
-                       && !atmci_test_and_set_completed(host, EVENT_STOP_SENT))
-               send_stop_cmd(host->mmc, data);
+       smp_wmb();
+       atmci_set_pending(host, EVENT_XFER_COMPLETE);
 }
 
-static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
+static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
 {
-       struct atmel_mci        *host = mmc_priv(mmc);
-
        mci_writel(host, IDR, MCI_CMDRDY);
 
-       if (atmci_is_completed(host, EVENT_STOP_SENT)) {
-               host->stop_status = status;
-               atmci_set_pending(host, EVENT_STOP_COMPLETE);
-       } else {
-               host->cmd_status = status;
-               atmci_set_pending(host, EVENT_CMD_COMPLETE);
-       }
-
+       host->cmd_status = status;
+       smp_wmb();
+       atmci_set_pending(host, EVENT_CMD_COMPLETE);
        tasklet_schedule(&host->tasklet);
 }
 
 static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 {
-       struct mmc_host         *mmc = dev_id;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci        *host = dev_id;
        u32                     status, mask, pending;
        unsigned int            pass_count = 0;
 
-       spin_lock(&mmc->lock);
-
        do {
                status = mci_readl(host, SR);
                mask = mci_readl(host, IMR);
@@ -946,13 +1401,18 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
                        mci_writel(host, IDR, ATMCI_DATA_ERROR_FLAGS
                                        | MCI_RXRDY | MCI_TXRDY);
                        pending &= mci_readl(host, IMR);
+
                        host->data_status = status;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_ERROR);
                        tasklet_schedule(&host->tasklet);
                }
                if (pending & MCI_NOTBUSY) {
-                       mci_writel(host, IDR, (MCI_NOTBUSY
-                                              | ATMCI_DATA_ERROR_FLAGS));
+                       mci_writel(host, IDR,
+                                       ATMCI_DATA_ERROR_FLAGS | MCI_NOTBUSY);
+                       if (!host->data_status)
+                               host->data_status = status;
+                       smp_wmb();
                        atmci_set_pending(host, EVENT_DATA_COMPLETE);
                        tasklet_schedule(&host->tasklet);
                }
@@ -962,18 +1422,15 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
                        atmci_write_data_pio(host);
 
                if (pending & MCI_CMDRDY)
-                       atmci_cmd_interrupt(mmc, status);
+                       atmci_cmd_interrupt(host, status);
        } while (pass_count++ < 5);
 
-       spin_unlock(&mmc->lock);
-
        return pass_count ? IRQ_HANDLED : IRQ_NONE;
 }
 
 static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 {
-       struct mmc_host         *mmc = dev_id;
-       struct atmel_mci        *host = mmc_priv(mmc);
+       struct atmel_mci_slot   *slot = dev_id;
 
        /*
         * Disable interrupts until the pin has stabilized and check
@@ -981,19 +1438,176 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
         * middle of the timer routine when this interrupt triggers.
         */
        disable_irq_nosync(irq);
-       mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
+       mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
 
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+
+static inline struct atmel_mci *
+dma_client_to_atmel_mci(struct dma_client *client)
+{
+       return container_of(client, struct atmel_mci, dma.client);
+}
+
+static enum dma_state_client atmci_dma_event(struct dma_client *client,
+               struct dma_chan *chan, enum dma_state state)
+{
+       struct atmel_mci        *host;
+       enum dma_state_client   ret = DMA_NAK;
+
+       host = dma_client_to_atmel_mci(client);
+
+       switch (state) {
+       case DMA_RESOURCE_AVAILABLE:
+               spin_lock_bh(&host->lock);
+               if (!host->dma.chan) {
+                       host->dma.chan = chan;
+                       ret = DMA_ACK;
+               }
+               spin_unlock_bh(&host->lock);
+
+               if (ret == DMA_ACK)
+                       dev_info(&host->pdev->dev,
+                                       "Using %s for DMA transfers\n",
+                                       chan->dev.bus_id);
+               break;
+
+       case DMA_RESOURCE_REMOVED:
+               spin_lock_bh(&host->lock);
+               if (host->dma.chan == chan) {
+                       host->dma.chan = NULL;
+                       ret = DMA_ACK;
+               }
+               spin_unlock_bh(&host->lock);
+
+               if (ret == DMA_ACK)
+                       dev_info(&host->pdev->dev,
+                                       "Lost %s, falling back to PIO\n",
+                                       chan->dev.bus_id);
+               break;
+
+       default:
+               break;
+       }
+
+
+       return ret;
+}
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
+
+static int __init atmci_init_slot(struct atmel_mci *host,
+               struct mci_slot_pdata *slot_data, unsigned int id,
+               u32 sdc_reg)
+{
+       struct mmc_host                 *mmc;
+       struct atmel_mci_slot           *slot;
+
+       mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       slot = mmc_priv(mmc);
+       slot->mmc = mmc;
+       slot->host = host;
+       slot->detect_pin = slot_data->detect_pin;
+       slot->wp_pin = slot_data->wp_pin;
+       slot->sdc_reg = sdc_reg;
+
+       mmc->ops = &atmci_ops;
+       mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
+       mmc->f_max = host->bus_hz / 2;
+       mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
+       if (slot_data->bus_width >= 4)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+       mmc->max_hw_segs = 64;
+       mmc->max_phys_segs = 64;
+       mmc->max_req_size = 32768 * 512;
+       mmc->max_blk_size = 32768;
+       mmc->max_blk_count = 512;
+
+       /* Assume card is present initially */
+       set_bit(ATMCI_CARD_PRESENT, &slot->flags);
+       if (gpio_is_valid(slot->detect_pin)) {
+               if (gpio_request(slot->detect_pin, "mmc_detect")) {
+                       dev_dbg(&mmc->class_dev, "no detect pin available\n");
+                       slot->detect_pin = -EBUSY;
+               } else if (gpio_get_value(slot->detect_pin)) {
+                       clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
+               }
+       }
+
+       if (!gpio_is_valid(slot->detect_pin))
+               mmc->caps |= MMC_CAP_NEEDS_POLL;
+
+       if (gpio_is_valid(slot->wp_pin)) {
+               if (gpio_request(slot->wp_pin, "mmc_wp")) {
+                       dev_dbg(&mmc->class_dev, "no WP pin available\n");
+                       slot->wp_pin = -EBUSY;
+               }
+       }
+
+       host->slot[id] = slot;
+       mmc_add_host(mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               int ret;
+
+               setup_timer(&slot->detect_timer, atmci_detect_change,
+                               (unsigned long)slot);
+
+               ret = request_irq(gpio_to_irq(slot->detect_pin),
+                               atmci_detect_interrupt,
+                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               "mmc-detect", slot);
+               if (ret) {
+                       dev_dbg(&mmc->class_dev,
+                               "could not request IRQ %d for detect pin\n",
+                               gpio_to_irq(slot->detect_pin));
+                       gpio_free(slot->detect_pin);
+                       slot->detect_pin = -EBUSY;
+               }
+       }
+
+       atmci_init_debugfs(slot);
+
+       return 0;
+}
+
+static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
+               unsigned int id)
+{
+       /* Debugfs stuff is cleaned up by mmc core */
+
+       set_bit(ATMCI_SHUTDOWN, &slot->flags);
+       smp_wmb();
+
+       mmc_remove_host(slot->mmc);
+
+       if (gpio_is_valid(slot->detect_pin)) {
+               int pin = slot->detect_pin;
+
+               free_irq(gpio_to_irq(pin), slot);
+               del_timer_sync(&slot->detect_timer);
+               gpio_free(pin);
+       }
+       if (gpio_is_valid(slot->wp_pin))
+               gpio_free(slot->wp_pin);
+
+       slot->host->slot[id] = NULL;
+       mmc_free_host(slot->mmc);
+}
+
 static int __init atmci_probe(struct platform_device *pdev)
 {
        struct mci_platform_data        *pdata;
-       struct atmel_mci *host;
-       struct mmc_host *mmc;
-       struct resource *regs;
-       int irq;
-       int ret;
+       struct atmel_mci                *host;
+       struct resource                 *regs;
+       unsigned int                    nr_slots;
+       int                             irq;
+       int                             ret;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!regs)
@@ -1005,15 +1619,13 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
 
-       mmc = mmc_alloc_host(sizeof(struct atmel_mci), &pdev->dev);
-       if (!mmc)
+       host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
+       if (!host)
                return -ENOMEM;
 
-       host = mmc_priv(mmc);
        host->pdev = pdev;
-       host->mmc = mmc;
-       host->detect_pin = pdata->detect_pin;
-       host->wp_pin = pdata->wp_pin;
+       spin_lock_init(&host->lock);
+       INIT_LIST_HEAD(&host->queue);
 
        host->mck = clk_get(&pdev->dev, "mci_clk");
        if (IS_ERR(host->mck)) {
@@ -1033,122 +1645,102 @@ static int __init atmci_probe(struct platform_device *pdev)
 
        host->mapbase = regs->start;
 
-       mmc->ops = &atmci_ops;
-       mmc->f_min = (host->bus_hz + 511) / 512;
-       mmc->f_max = host->bus_hz / 2;
-       mmc->ocr_avail  = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps |= MMC_CAP_4_BIT_DATA;
-
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
-       mmc->max_req_size = 32768 * 512;
-       mmc->max_blk_size = 32768;
-       mmc->max_blk_count = 512;
-
-       tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)mmc);
+       tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
 
-       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, mmc);
+       ret = request_irq(irq, atmci_interrupt, 0, pdev->dev.bus_id, host);
        if (ret)
                goto err_request_irq;
 
-       /* Assume card is present if we don't have a detect pin */
-       host->present = 1;
-       if (gpio_is_valid(host->detect_pin)) {
-               if (gpio_request(host->detect_pin, "mmc_detect")) {
-                       dev_dbg(&mmc->class_dev, "no detect pin available\n");
-                       host->detect_pin = -1;
-               } else {
-                       host->present = !gpio_get_value(host->detect_pin);
-               }
-       }
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (pdata->dma_slave) {
+               struct dma_slave *slave = pdata->dma_slave;
 
-       if (!gpio_is_valid(host->detect_pin))
-               mmc->caps |= MMC_CAP_NEEDS_POLL;
+               slave->tx_reg = regs->start + MCI_TDR;
+               slave->rx_reg = regs->start + MCI_RDR;
 
-       if (gpio_is_valid(host->wp_pin)) {
-               if (gpio_request(host->wp_pin, "mmc_wp")) {
-                       dev_dbg(&mmc->class_dev, "no WP pin available\n");
-                       host->wp_pin = -1;
-               }
+               /* Try to grab a DMA channel */
+               host->dma.client.event_callback = atmci_dma_event;
+               dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask);
+               host->dma.client.slave = slave;
+
+               dma_async_client_register(&host->dma.client);
+               dma_async_client_chan_request(&host->dma.client);
+       } else {
+               dev_notice(&pdev->dev, "DMA not available, using PIO\n");
        }
+#endif /* CONFIG_MMC_ATMELMCI_DMA */
 
        platform_set_drvdata(pdev, host);
 
-       mmc_add_host(mmc);
-
-       if (gpio_is_valid(host->detect_pin)) {
-               setup_timer(&host->detect_timer, atmci_detect_change,
-                               (unsigned long)host);
-
-               ret = request_irq(gpio_to_irq(host->detect_pin),
-                               atmci_detect_interrupt,
-                               IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
-                               "mmc-detect", mmc);
-               if (ret) {
-                       dev_dbg(&mmc->class_dev,
-                               "could not request IRQ %d for detect pin\n",
-                               gpio_to_irq(host->detect_pin));
-                       gpio_free(host->detect_pin);
-                       host->detect_pin = -1;
-               }
+       /* We need at least one slot to succeed */
+       nr_slots = 0;
+       ret = -ENODEV;
+       if (pdata->slot[0].bus_width) {
+               ret = atmci_init_slot(host, &pdata->slot[0],
+                               MCI_SDCSEL_SLOT_A, 0);
+               if (!ret)
+                       nr_slots++;
+       }
+       if (pdata->slot[1].bus_width) {
+               ret = atmci_init_slot(host, &pdata->slot[1],
+                               MCI_SDCSEL_SLOT_B, 1);
+               if (!ret)
+                       nr_slots++;
        }
 
-       dev_info(&mmc->class_dev,
-                       "Atmel MCI controller at 0x%08lx irq %d\n",
-                       host->mapbase, irq);
+       if (!nr_slots)
+               goto err_init_slot;
 
-       atmci_init_debugfs(host);
+       dev_info(&pdev->dev,
+                       "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
+                       host->mapbase, irq, nr_slots);
 
        return 0;
 
+err_init_slot:
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (pdata->dma_slave)
+               dma_async_client_unregister(&host->dma.client);
+#endif
+       free_irq(irq, host);
 err_request_irq:
        iounmap(host->regs);
 err_ioremap:
        clk_put(host->mck);
 err_clk_get:
-       mmc_free_host(mmc);
+       kfree(host);
        return ret;
 }
 
 static int __exit atmci_remove(struct platform_device *pdev)
 {
-       struct atmel_mci *host = platform_get_drvdata(pdev);
+       struct atmel_mci        *host = platform_get_drvdata(pdev);
+       unsigned int            i;
 
        platform_set_drvdata(pdev, NULL);
 
-       if (host) {
-               /* Debugfs stuff is cleaned up by mmc core */
-
-               if (gpio_is_valid(host->detect_pin)) {
-                       int pin = host->detect_pin;
-
-                       /* Make sure the timer doesn't enable the interrupt */
-                       host->detect_pin = -1;
-                       smp_wmb();
-
-                       free_irq(gpio_to_irq(pin), host->mmc);
-                       del_timer_sync(&host->detect_timer);
-                       gpio_free(pin);
-               }
-
-               mmc_remove_host(host->mmc);
+       for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               if (host->slot[i])
+                       atmci_cleanup_slot(host->slot[i], i);
+       }
 
-               clk_enable(host->mck);
-               mci_writel(host, IDR, ~0UL);
-               mci_writel(host, CR, MCI_CR_MCIDIS);
-               mci_readl(host, SR);
-               clk_disable(host->mck);
+       clk_enable(host->mck);
+       mci_writel(host, IDR, ~0UL);
+       mci_writel(host, CR, MCI_CR_MCIDIS);
+       mci_readl(host, SR);
+       clk_disable(host->mck);
 
-               if (gpio_is_valid(host->wp_pin))
-                       gpio_free(host->wp_pin);
+#ifdef CONFIG_MMC_ATMELMCI_DMA
+       if (host->dma.client.slave)
+               dma_async_client_unregister(&host->dma.client);
+#endif
 
-               free_irq(platform_get_irq(pdev, 0), host->mmc);
-               iounmap(host->regs);
+       free_irq(platform_get_irq(pdev, 0), host);
+       iounmap(host->regs);
 
-               clk_put(host->mck);
+       clk_put(host->mck);
+       kfree(host);
 
-               mmc_free_host(host->mmc);
-       }
        return 0;
 }
 
index 7503b81374e0783690df20afbc88da0b02a75e85..07faf5412a1ffb210cd0741e9383d0a2392fff89 100644 (file)
@@ -95,8 +95,6 @@
  * reads which takes nowhere near that long.  Older cards may be able to use
  * shorter timeouts ... but why bother?
  */
-#define readblock_timeout      ktime_set(0, 100 * 1000 * 1000)
-#define writeblock_timeout     ktime_set(0, 250 * 1000 * 1000)
 #define r1b_timeout            ktime_set(3, 0)
 
 
@@ -220,9 +218,9 @@ mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
        return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
 }
 
-static int mmc_spi_readtoken(struct mmc_spi_host *host)
+static int mmc_spi_readtoken(struct mmc_spi_host *host, ktime_t timeout)
 {
-       return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+       return mmc_spi_skip(host, timeout, 1, 0xff);
 }
 
 
@@ -605,7 +603,8 @@ mmc_spi_setup_data_message(
  * Return negative errno, else success.
  */
 static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
+       ktime_t timeout)
 {
        struct spi_device       *spi = host->spi;
        int                     status, i;
@@ -673,7 +672,7 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
                if (scratch->status[i] != 0)
                        return 0;
        }
-       return mmc_spi_wait_unbusy(host, writeblock_timeout);
+       return mmc_spi_wait_unbusy(host, timeout);
 }
 
 /*
@@ -693,7 +692,8 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
  * STOP_TRANSMISSION command.
  */
 static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
+       ktime_t timeout)
 {
        struct spi_device       *spi = host->spi;
        int                     status;
@@ -707,7 +707,7 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
                return status;
        status = scratch->status[0];
        if (status == 0xff || status == 0)
-               status = mmc_spi_readtoken(host);
+               status = mmc_spi_readtoken(host, timeout);
 
        if (status == SPI_TOKEN_SINGLE) {
                if (host->dma_dev) {
@@ -778,6 +778,8 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
        struct scatterlist      *sg;
        unsigned                n_sg;
        int                     multiple = (data->blocks > 1);
+       u32                     clock_rate;
+       ktime_t                 timeout;
 
        if (data->flags & MMC_DATA_READ)
                direction = DMA_FROM_DEVICE;
@@ -786,6 +788,14 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
        mmc_spi_setup_data_message(host, multiple, direction);
        t = &host->t;
 
+       if (t->speed_hz)
+               clock_rate = t->speed_hz;
+       else
+               clock_rate = spi->max_speed_hz;
+
+       timeout = ktime_add_ns(ktime_set(0, 0), data->timeout_ns +
+                       data->timeout_clks * 1000000 / clock_rate);
+
        /* Handle scatterlist segments one at a time, with synch for
         * each 512-byte block
         */
@@ -832,9 +842,9 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                                t->len);
 
                        if (direction == DMA_TO_DEVICE)
-                               status = mmc_spi_writeblock(host, t);
+                               status = mmc_spi_writeblock(host, t, timeout);
                        else
-                               status = mmc_spi_readblock(host, t);
+                               status = mmc_spi_readblock(host, t, timeout);
                        if (status < 0)
                                break;
 
@@ -917,7 +927,7 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
                        if (scratch->status[tmp] != 0)
                                return;
                }
-               tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+               tmp = mmc_spi_wait_unbusy(host, timeout);
                if (tmp < 0 && !data->error)
                        data->error = tmp;
        }
index fcb14c2346ccd186f0aef38b96f6405bb1380dc1..0a84f10d719c2e2a8f4c37b4696bc3f1dc1e7d2b 100644 (file)
@@ -144,7 +144,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                          SDHCI_QUIRK_32BIT_DMA_SIZE |
                          SDHCI_QUIRK_32BIT_ADMA_SIZE |
                          SDHCI_QUIRK_RESET_AFTER_REQUEST |
-                         SDHCI_QUIRK_BROKEN_SMALL_PIO;
+                         SDHCI_QUIRK_BROKEN_SMALL_PIO |
+                         SDHCI_QUIRK_FORCE_HIGHSPEED;
        }
 
        /*
index e3a8133560a2b41a19f15dd193a83c80d5727e4f..30f64b1f2354af215cfb1dc377b115637902cd23 100644 (file)
@@ -177,7 +177,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
 {
        unsigned long flags;
        size_t blksize, len, chunk;
-       u32 scratch;
+       u32 uninitialized_var(scratch);
        u8 *buf;
 
        DBG("PIO reading\n");
@@ -1154,7 +1154,7 @@ static void sdhci_tasklet_card(unsigned long param)
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+       mmc_detect_change(host->mmc, msecs_to_jiffies(200));
 }
 
 static void sdhci_tasklet_finish(unsigned long param)
@@ -1266,9 +1266,31 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                        SDHCI_INT_INDEX))
                host->cmd->error = -EILSEQ;
 
-       if (host->cmd->error)
+       if (host->cmd->error) {
                tasklet_schedule(&host->finish_tasklet);
-       else if (intmask & SDHCI_INT_RESPONSE)
+               return;
+       }
+
+       /*
+        * The host can send and interrupt when the busy state has
+        * ended, allowing us to wait without wasting CPU cycles.
+        * Unfortunately this is overloaded on the "data complete"
+        * interrupt, so we need to take some care when handling
+        * it.
+        *
+        * Note: The 1.0 specification is a bit ambiguous about this
+        *       feature so there might be some problems with older
+        *       controllers.
+        */
+       if (host->cmd->flags & MMC_RSP_BUSY) {
+               if (host->cmd->data)
+                       DBG("Cannot wait for busy signal when also "
+                               "doing a data transfer");
+               else
+                       return;
+       }
+
+       if (intmask & SDHCI_INT_RESPONSE)
                sdhci_finish_command(host);
 }
 
@@ -1278,11 +1300,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 
        if (!host->data) {
                /*
-                * A data end interrupt is sent together with the response
-                * for the stop command.
+                * The "data complete" interrupt is also used to
+                * indicate that a busy state has ended. See comment
+                * above in sdhci_cmd_irq().
                 */
-               if (intmask & SDHCI_INT_DATA_END)
-                       return;
+               if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
+                       if (intmask & SDHCI_INT_DATA_END) {
+                               sdhci_finish_command(host);
+                               return;
+                       }
+               }
 
                printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
                        "though no data operation was in progress.\n",
@@ -1604,7 +1631,8 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->f_max = host->max_clk;
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
-       if (caps & SDHCI_CAN_DO_HISPD)
+       if ((caps & SDHCI_CAN_DO_HISPD) ||
+               (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
                mmc->caps |= MMC_CAP_SD_HIGHSPEED;
 
        mmc->ocr_avail = 0;
index 197d4a05f4ae975ecf1fe600adcf9ec2ce79fbb5..31f4b1528e76137a43219c5b8d8ba7fb82d625c8 100644 (file)
@@ -208,6 +208,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
 /* Controller has an issue with buffer bits for small transfers */
 #define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
+/* Controller supports high speed but doesn't have the caps bit set */
+#define SDHCI_QUIRK_FORCE_HIGHSPEED                    (1<<14)
 
        int                     irq;            /* Device IRQ */
        void __iomem *          ioaddr;         /* Mapped address */
index 0d7c88396c888a3d367d84f7b3e654b77124429a..fd7a1017399a069da8f8e78dd62a08d1ad6dcf3e 100644 (file)
@@ -1,13 +1,10 @@
-/*
- *
- * sun_uflash - Driver implementation for user-programmable flash
- * present on many Sun Microsystems SME boardsets.
+/* sun_uflash.c - Driver for user-programmable flash on
+ *                Sun Microsystems SME boardsets.
  *
  * This driver does NOT provide access to the OBP-flash for
  * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead.
  *
  * Copyright (c) 2001 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
@@ -16,8 +13,8 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/prom.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/mtd/map.h>
 
 #define UFLASH_OBPNAME "flashprom"
-#define UFLASH_DEVNAME         "userflash"
+#define DRIVER_NAME    "sun_uflash"
+#define PFX            DRIVER_NAME ": "
 
 #define UFLASH_WINDOW_SIZE     0x200000
 #define UFLASH_BUSWIDTH                1                       /* EBus is 8-bit */
 
 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
 MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_SUPPORTED_DEVICE(DRIVER_NAME);
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
-static LIST_HEAD(device_list);
 struct uflash_dev {
        const char              *name;  /* device name */
        struct map_info         map;    /* mtd map info */
        struct mtd_info         *mtd;   /* mtd info */
 };
 
-
 struct map_info uflash_map_templ = {
        .name =         "SUNW,???-????",
        .size =         UFLASH_WINDOW_SIZE,
        .bankwidth =    UFLASH_BUSWIDTH,
 };
 
-int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
+int uflash_devinit(struct of_device *op, struct device_node *dp)
 {
        struct uflash_dev *up;
-       struct resource *res;
 
-       res = &edev->resource[0];
-
-       if (edev->num_addrs != 1) {
+       if (op->resource[1].flags) {
                /* Non-CFI userflash device-- once I find one we
                 * can work on supporting it.
                 */
-               printk("%s: unsupported device at 0x%llx (%d regs): " \
-                       "email ebrower@usa.net\n",
-                      dp->full_name, (unsigned long long)res->start,
-                      edev->num_addrs);
+               printk(KERN_ERR PFX "Unsupported device at %s, 0x%llx\n",
+                      dp->full_name, (unsigned long long)op->resource[0].start);
 
                return -ENODEV;
        }
 
        up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
-       if (!up)
+       if (!up) {
+               printk(KERN_ERR PFX "Cannot allocate struct uflash_dev\n");
                return -ENOMEM;
+       }
 
        /* copy defaults and tweak parameters */
        memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
-       up->map.size = (res->end - res->start) + 1UL;
+
+       up->map.size = resource_size(&op->resource[0]);
 
        up->name = of_get_property(dp, "model", NULL);
        if (up->name && 0 < strlen(up->name))
                up->map.name = (char *)up->name;
 
-       up->map.phys = res->start;
+       up->map.phys = op->resource[0].start;
 
-       up->map.virt = ioremap_nocache(res->start, up->map.size);
+       up->map.virt = of_ioremap(&op->resource[0], 0, up->map.size,
+                                 DRIVER_NAME);
        if (!up->map.virt) {
-               printk("%s: Failed to map device.\n", dp->full_name);
+               printk(KERN_ERR PFX "Failed to map device.\n");
                kfree(up);
 
                return -EINVAL;
@@ -97,7 +92,7 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
        /* MTD registration */
        up->mtd = do_map_probe("cfi_probe", &up->map);
        if (!up->mtd) {
-               iounmap(up->map.virt);
+               of_iounmap(&op->resource[0], up->map.virt, up->map.size);
                kfree(up);
 
                return -ENXIO;
@@ -107,32 +102,34 @@ int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
 
        add_mtd_device(up->mtd);
 
-       dev_set_drvdata(&edev->ofdev.dev, up);
+       dev_set_drvdata(&op->dev, up);
 
        return 0;
 }
 
-static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit uflash_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device_node *dp = op->node;
 
-       if (of_find_property(dp, "user", NULL))
+       /* Flashprom must have the "user" property in order to
+        * be used by this driver.
+        */
+       if (!of_find_property(dp, "user", NULL))
                return -ENODEV;
 
-       return uflash_devinit(edev, dp);
+       return uflash_devinit(op, dp);
 }
 
-static int __devexit uflash_remove(struct of_device *dev)
+static int __devexit uflash_remove(struct of_device *op)
 {
-       struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+       struct uflash_dev *up = dev_get_drvdata(&op->dev);
 
        if (up->mtd) {
                del_mtd_device(up->mtd);
                map_destroy(up->mtd);
        }
        if (up->map.virt) {
-               iounmap(up->map.virt);
+               of_iounmap(&op->resource[0], up->map.virt, up->map.size);
                up->map.virt = NULL;
        }
 
@@ -141,7 +138,7 @@ static int __devexit uflash_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id uflash_match[] = {
+static const struct of_device_id uflash_match[] = {
        {
                .name = UFLASH_OBPNAME,
        },
@@ -151,7 +148,7 @@ static struct of_device_id uflash_match[] = {
 MODULE_DEVICE_TABLE(of, uflash_match);
 
 static struct of_platform_driver uflash_driver = {
-       .name           = UFLASH_DEVNAME,
+       .name           = DRIVER_NAME,
        .match_table    = uflash_match,
        .probe          = uflash_probe,
        .remove         = __devexit_p(uflash_remove),
@@ -159,7 +156,7 @@ static struct of_platform_driver uflash_driver = {
 
 static int __init uflash_init(void)
 {
-       return of_register_driver(&uflash_driver, &ebus_bus_type);
+       return of_register_driver(&uflash_driver, &of_bus_type);
 }
 
 static void __exit uflash_exit(void)
index 3bafaede7916f844696cbdef0c6e01fa8ede6b1e..fac82152e4c8795287fc5c2b7dc10481cc994093 100644 (file)
@@ -1047,6 +1047,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
 
        netdev->features |= NETIF_F_LLTX;
 
+       netdev->vlan_features |= NETIF_F_TSO;
+       netdev->vlan_features |= NETIF_F_TSO6;
+       netdev->vlan_features |= NETIF_F_HW_CSUM;
+       netdev->vlan_features |= NETIF_F_SG;
+
        adapter->en_mng_pt = e1000_enable_mng_pass_thru(hw);
 
        /* initialize eeprom parameters */
index 06e682334c7e19ace535c67eb811fa5a020ced47..3ad7589d6a1c36b341920e6a2c4548d34de3ff92 100644 (file)
@@ -1,6 +1,6 @@
 /* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
  *
- * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 static char version[] =
@@ -22,6 +22,9 @@ static char version[] =
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <net/dst.h>
 #include <net/arp.h>
@@ -33,7 +36,6 @@ static char version[] =
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -243,7 +245,8 @@ static void myri_clean_rings(struct myri_eth *mp)
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&rxd->myri_scatters[0].addr);
-                       sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                        RX_ALLOC_SIZE, DMA_FROM_DEVICE);
                        dev_kfree_skb(mp->rx_skbs[i]);
                        mp->rx_skbs[i] = NULL;
                }
@@ -259,7 +262,9 @@ static void myri_clean_rings(struct myri_eth *mp)
                        u32 dma_addr;
 
                        dma_addr = sbus_readl(&txd->myri_gathers[0].addr);
-                       sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE);
+                       dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                        (skb->len + 3) & ~3,
+                                        DMA_TO_DEVICE);
                        dev_kfree_skb(mp->tx_skbs[i]);
                        mp->tx_skbs[i] = NULL;
                }
@@ -288,7 +293,9 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
                skb->dev = dev;
                skb_put(skb, RX_ALLOC_SIZE);
 
-               dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+               dma_addr = dma_map_single(&mp->myri_op->dev,
+                                         skb->data, RX_ALLOC_SIZE,
+                                         DMA_FROM_DEVICE);
                sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr);
                sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len);
                sbus_writel(i, &rxd[i].ctx);
@@ -344,7 +351,8 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
 
                DTX(("SKB[%d] ", entry));
                dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr);
-               sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
+               dma_unmap_single(&mp->myri_op->dev, dma_addr,
+                                skb->len, DMA_TO_DEVICE);
                dev_kfree_skb(skb);
                mp->tx_skbs[entry] = NULL;
                dev->stats.tx_packets++;
@@ -423,9 +431,9 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
 
                /* Check for errors. */
                DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum));
-               sbus_dma_sync_single_for_cpu(mp->myri_sdev,
-                                            sbus_readl(&rxd->myri_scatters[0].addr),
-                                            RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
+               dma_sync_single_for_cpu(&mp->myri_op->dev,
+                                       sbus_readl(&rxd->myri_scatters[0].addr),
+                                       RX_ALLOC_SIZE, DMA_FROM_DEVICE);
                if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
                        DRX(("ERROR["));
                        dev->stats.rx_errors++;
@@ -442,10 +450,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                        drops++;
                        DRX(("DROP "));
                        dev->stats.rx_dropped++;
-                       sbus_dma_sync_single_for_device(mp->myri_sdev,
-                                                       sbus_readl(&rxd->myri_scatters[0].addr),
-                                                       RX_ALLOC_SIZE,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&mp->myri_op->dev,
+                                                  sbus_readl(&rxd->myri_scatters[0].addr),
+                                                  RX_ALLOC_SIZE,
+                                                  DMA_FROM_DEVICE);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
                        sbus_writel(1, &rxd->num_sg);
@@ -464,17 +472,17 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
                                DRX(("skb_alloc(FAILED) "));
                                goto drop_it;
                        }
-                       sbus_unmap_single(mp->myri_sdev,
-                                         sbus_readl(&rxd->myri_scatters[0].addr),
-                                         RX_ALLOC_SIZE,
-                                         SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&mp->myri_op->dev,
+                                        sbus_readl(&rxd->myri_scatters[0].addr),
+                                        RX_ALLOC_SIZE,
+                                        DMA_FROM_DEVICE);
                        mp->rx_skbs[index] = new_skb;
                        new_skb->dev = dev;
                        skb_put(new_skb, RX_ALLOC_SIZE);
-                       dma_addr = sbus_map_single(mp->myri_sdev,
-                                                  new_skb->data,
-                                                  RX_ALLOC_SIZE,
-                                                  SBUS_DMA_FROMDEVICE);
+                       dma_addr = dma_map_single(&mp->myri_op->dev,
+                                                 new_skb->data,
+                                                 RX_ALLOC_SIZE,
+                                                 DMA_FROM_DEVICE);
                        sbus_writel(dma_addr, &rxd->myri_scatters[0].addr);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
@@ -500,10 +508,10 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
 
                        /* Reuse original ring buffer. */
                        DRX(("reuse "));
-                       sbus_dma_sync_single_for_device(mp->myri_sdev,
-                                                       sbus_readl(&rxd->myri_scatters[0].addr),
-                                                       RX_ALLOC_SIZE,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&mp->myri_op->dev,
+                                                  sbus_readl(&rxd->myri_scatters[0].addr),
+                                                  RX_ALLOC_SIZE,
+                                                  DMA_FROM_DEVICE);
                        sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len);
                        sbus_writel(index, &rxd->ctx);
                        sbus_writel(1, &rxd->num_sg);
@@ -652,7 +660,8 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
                sbus_writew((skb->data[4] << 8) | skb->data[5], &txd->addr[3]);
        }
 
-       dma_addr = sbus_map_single(mp->myri_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+       dma_addr = dma_map_single(&mp->myri_op->dev, skb->data,
+                                 len, DMA_TO_DEVICE);
        sbus_writel(dma_addr, &txd->myri_gathers[0].addr);
        sbus_writel(len, &txd->myri_gathers[0].len);
        sbus_writel(1, &txd->num_sg);
@@ -891,30 +900,30 @@ static const struct header_ops myri_header_ops = {
        .cache_update   = myri_header_cache_update,
 };
 
-static int __devinit myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       static int num;
+       struct device_node *dp = op->node;
        static unsigned version_printed;
        struct net_device *dev;
-       struct myri_eth *mp;
-       unsigned char prop_buf[32];
-       int i;
        DECLARE_MAC_BUF(mac);
+       struct myri_eth *mp;
+       const void *prop;
+       static int num;
+       int i, len;
 
-       DET(("myri_ether_init(%p,%d):\n", sdev, num));
+       DET(("myri_ether_init(%p,%d):\n", op, num));
        dev = alloc_etherdev(sizeof(struct myri_eth));
-
        if (!dev)
                return -ENOMEM;
 
        if (version_printed++ == 0)
                printk(version);
 
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
-       mp = (struct myri_eth *) dev->priv;
+       mp = netdev_priv(dev);
        spin_lock_init(&mp->irq_lock);
-       mp->myri_sdev = sdev;
+       mp->myri_op = op;
 
        /* Clean out skb arrays. */
        for (i = 0; i < (RX_RING_SIZE + 1); i++)
@@ -924,55 +933,44 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                mp->tx_skbs[i] = NULL;
 
        /* First check for EEPROM information. */
-       i = prom_getproperty(sdev->prom_node, "myrinet-eeprom-info",
-                            (char *)&mp->eeprom, sizeof(struct myri_eeprom));
-       DET(("prom_getprop(myrinet-eeprom-info) returns %d\n", i));
-       if (i == 0 || i == -1) {
+       prop = of_get_property(dp, "myrinet-eeprom-info", &len);
+
+       if (prop)
+               memcpy(&mp->eeprom, prop, sizeof(struct myri_eeprom));
+       if (!prop) {
                /* No eeprom property, must cook up the values ourselves. */
                DET(("No EEPROM: "));
                mp->eeprom.bus_type = BUS_TYPE_SBUS;
-               mp->eeprom.cpuvers = prom_getintdefault(sdev->prom_node,"cpu_version",0);
-               mp->eeprom.cval = prom_getintdefault(sdev->prom_node,"clock_value",0);
-               mp->eeprom.ramsz = prom_getintdefault(sdev->prom_node,"sram_size",0);
-               DET(("cpuvers[%d] cval[%d] ramsz[%d]\n", mp->eeprom.cpuvers,
-                    mp->eeprom.cval, mp->eeprom.ramsz));
-               if (mp->eeprom.cpuvers == 0) {
-                       DET(("EEPROM: cpuvers was zero, setting to %04x\n",CPUVERS_2_3));
+               mp->eeprom.cpuvers =
+                       of_getintprop_default(dp, "cpu_version", 0);
+               mp->eeprom.cval =
+                       of_getintprop_default(dp, "clock_value", 0);
+               mp->eeprom.ramsz = of_getintprop_default(dp, "sram_size", 0);
+               if (!mp->eeprom.cpuvers)
                        mp->eeprom.cpuvers = CPUVERS_2_3;
-               }
-               if (mp->eeprom.cpuvers < CPUVERS_3_0) {
-                       DET(("EEPROM: cpuvers < CPUVERS_3_0, clockval set to zero.\n"));
+               if (mp->eeprom.cpuvers < CPUVERS_3_0)
                        mp->eeprom.cval = 0;
-               }
-               if (mp->eeprom.ramsz == 0) {
-                       DET(("EEPROM: ramsz == 0, setting to 128k\n"));
+               if (!mp->eeprom.ramsz)
                        mp->eeprom.ramsz = (128 * 1024);
-               }
-               i = prom_getproperty(sdev->prom_node, "myrinet-board-id",
-                                    &prop_buf[0], 10);
-               DET(("EEPROM: prom_getprop(myrinet-board-id) returns %d\n", i));
-               if ((i != 0) && (i != -1))
-                       memcpy(&mp->eeprom.id[0], &prop_buf[0], 6);
+
+               prop = of_get_property(dp, "myrinet-board-id", &len);
+               if (prop)
+                       memcpy(&mp->eeprom.id[0], prop, 6);
                else
                        set_boardid_from_idprom(mp, num);
-               i = prom_getproperty(sdev->prom_node, "fpga_version",
-                                    &mp->eeprom.fvers[0], 32);
-               DET(("EEPROM: prom_getprop(fpga_version) returns %d\n", i));
-               if (i == 0 || i == -1)
+
+               prop = of_get_property(dp, "fpga_version", &len);
+               if (prop)
+                       memcpy(&mp->eeprom.fvers[0], prop, 32);
+               else
                        memset(&mp->eeprom.fvers[0], 0, 32);
 
                if (mp->eeprom.cpuvers == CPUVERS_4_1) {
-                       DET(("EEPROM: cpuvers CPUVERS_4_1, "));
-                       if (mp->eeprom.ramsz == (128 * 1024)) {
-                               DET(("ramsize 128k, setting to 256k, "));
+                       if (mp->eeprom.ramsz == (128 * 1024))
                                mp->eeprom.ramsz = (256 * 1024);
-                       }
-                       if ((mp->eeprom.cval==0x40414041)||(mp->eeprom.cval==0x90449044)){
-                               DET(("changing cval from %08x to %08x ",
-                                    mp->eeprom.cval, 0x50e450e4));
+                       if ((mp->eeprom.cval == 0x40414041) ||
+                           (mp->eeprom.cval == 0x90449044))
                                mp->eeprom.cval = 0x50e450e4;
-                       }
-                       DET(("\n"));
                }
        }
 #ifdef DEBUG_DETECT
@@ -991,8 +989,8 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                 * XXX only a valid version for PCI cards?  Ask feldy...
                 */
                DET(("Mapping regs for cpuvers < CPUVERS_4_0\n"));
-               mp->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                       mp->reg_size, "MyriCOM Regs");
+               mp->regs = of_ioremap(&op->resource[0], 0,
+                                     mp->reg_size, "MyriCOM Regs");
                if (!mp->regs) {
                        printk("MyriCOM: Cannot map MyriCOM registers.\n");
                        goto err;
@@ -1001,13 +999,12 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                mp->lregs = mp->lanai + (0x10000 * 2);
        } else {
                DET(("Mapping regs for cpuvers >= CPUVERS_4_0\n"));
-               mp->cregs = sbus_ioremap(&sdev->resource[0], 0,
-                                        PAGE_SIZE, "MyriCOM Control Regs");
-               mp->lregs = sbus_ioremap(&sdev->resource[0], (256 * 1024),
+               mp->cregs = of_ioremap(&op->resource[0], 0,
+                                      PAGE_SIZE, "MyriCOM Control Regs");
+               mp->lregs = of_ioremap(&op->resource[0], (256 * 1024),
                                         PAGE_SIZE, "MyriCOM LANAI Regs");
-               mp->lanai =
-                       sbus_ioremap(&sdev->resource[0], (512 * 1024),
-                                    mp->eeprom.ramsz, "MyriCOM SRAM");
+               mp->lanai = of_ioremap(&op->resource[0], (512 * 1024),
+                                      mp->eeprom.ramsz, "MyriCOM SRAM");
        }
        DET(("Registers mapped: cregs[%p] lregs[%p] lanai[%p]\n",
             mp->cregs, mp->lregs, mp->lanai));
@@ -1039,16 +1036,15 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
        myri_reset_on(mp->cregs);
 
        /* Get the supported DVMA burst sizes from our SBUS. */
-       mp->myri_bursts = prom_getintdefault(mp->myri_sdev->bus->prom_node,
-                                            "burst-sizes", 0x00);
-
-       if (!sbus_can_burst64(sdev))
+       mp->myri_bursts = of_getintprop_default(dp->parent,
+                                               "burst-sizes", 0x00);
+       if (!sbus_can_burst64())
                mp->myri_bursts &= ~(DMA_BURST64);
 
        DET(("MYRI bursts %02x\n", mp->myri_bursts));
 
        /* Encode SBUS interrupt level in second control register. */
-       i = prom_getint(sdev->prom_node, "interrupts");
+       i = of_getintprop_default(dp, "interrupts", 0);
        if (i == 0)
                i = 4;
        DET(("prom_getint(interrupts)==%d, irqlvl set to %04x\n",
@@ -1063,7 +1059,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
        dev->tx_timeout = &myri_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
        dev->set_multicast_list = &myri_set_multicast;
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
 
        /* Register interrupt handler now. */
        DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1088,7 +1084,7 @@ static int __devinit myri_ether_init(struct sbus_dev *sdev)
                goto err_free_irq;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, mp);
+       dev_set_drvdata(&op->dev, mp);
 
        num++;
 
@@ -1105,17 +1101,9 @@ err:
        return -ENODEV;
 }
 
-
-static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return myri_ether_init(sdev);
-}
-
-static int __devexit myri_sbus_remove(struct of_device *dev)
+static int __devexit myri_sbus_remove(struct of_device *op)
 {
-       struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+       struct myri_eth *mp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = mp->dev;
 
        unregister_netdev(net_dev);
@@ -1123,21 +1111,21 @@ static int __devexit myri_sbus_remove(struct of_device *dev)
        free_irq(net_dev->irq, net_dev);
 
        if (mp->eeprom.cpuvers < CPUVERS_4_0) {
-               sbus_iounmap(mp->regs, mp->reg_size);
+               of_iounmap(&op->resource[0], mp->regs, mp->reg_size);
        } else {
-               sbus_iounmap(mp->cregs, PAGE_SIZE);
-               sbus_iounmap(mp->lregs, (256 * 1024));
-               sbus_iounmap(mp->lanai, (512 * 1024));
+               of_iounmap(&op->resource[0], mp->cregs, PAGE_SIZE);
+               of_iounmap(&op->resource[0], mp->lregs, (256 * 1024));
+               of_iounmap(&op->resource[0], mp->lanai, (512 * 1024));
        }
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id myri_sbus_match[] = {
+static const struct of_device_id myri_sbus_match[] = {
        {
                .name = "MYRICOM,mlanai",
        },
@@ -1158,7 +1146,7 @@ static struct of_platform_driver myri_sbus_driver = {
 
 static int __init myri_sbus_init(void)
 {
-       return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&myri_sbus_driver, &of_bus_type);
 }
 
 static void __exit myri_sbus_exit(void)
index 5d93fcc95d55e7db5240b956ee3109d26331d42d..ff363e95d9cfadd7504544904042f114d4041d57 100644 (file)
@@ -288,7 +288,7 @@ struct myri_eth {
        struct myri_eeprom              eeprom;         /* Local copy of EEPROM.      */
        unsigned int                    reg_size;       /* Size of register space.    */
        unsigned int                    shmem_base;     /* Offset to shared ram.      */
-       struct sbus_dev                 *myri_sdev;     /* Our SBUS device struct.    */
+       struct of_device                *myri_op;       /* Our OF device struct.    */
 };
 
 /* We use this to acquire receive skb's that we can DMA directly into. */
index e3be81eba8a44c9f9a96077558450f9203e8b46c..ebc81270290339d09b94c3f6e46a8a921a68b2a4 100644 (file)
@@ -9130,7 +9130,7 @@ static int __devexit niu_of_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id niu_match[] = {
+static const struct of_device_id niu_match[] = {
        {
                .name = "network",
                .compatible = "SUNW,niusl",
index 02cc064c2c8b8319836a7f443c6f0ff75867fb79..3d19d00e8eecf1c1af4110b3fd1e1bf6e8327d8b 100644 (file)
@@ -722,6 +722,9 @@ static void smc911x_phy_detect(struct net_device *dev)
                                                break;
                                        }
                                }
+                               if (phyaddr < 32)
+                                       /* Found an external PHY */
+                                       break;
                        }
                default:
                        /* Internal media only */
index 31e7384e312ad71a437144acb030730e34771d8e..018d0fca9422bc2760c835b6f9a9de46670da7e1 100644 (file)
@@ -1,7 +1,6 @@
-/* $Id: sunbmac.c,v 1.30 2002/01/15 06:48:55 davem Exp $
- * sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
+/* sunbmac.c: Driver for Sparc BigMAC 100baseT ethernet adapters.
  *
- * Copyright (C) 1997, 1998, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997, 1998, 1999, 2003, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -23,6 +22,9 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/auxio.h>
 #include <asm/byteorder.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 #include <asm/system.h>
 
 #include "sunbmac.h"
 
 #define DRV_NAME       "sunbmac"
-#define DRV_VERSION    "2.0"
-#define DRV_RELDATE    "11/24/03"
-#define DRV_AUTHOR     "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION    "2.1"
+#define DRV_RELDATE    "August 26, 2008"
+#define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -96,8 +97,8 @@ static int qec_global_reset(void __iomem *gregs)
 
 static void qec_init(struct bigmac *bp)
 {
+       struct of_device *qec_op = bp->qec_op;
        void __iomem *gregs = bp->gregs;
-       struct sbus_dev *qec_sdev = bp->qec_sdev;
        u8 bsizes = bp->bigmac_bursts;
        u32 regval;
 
@@ -112,13 +113,13 @@ static void qec_init(struct bigmac *bp)
        sbus_writel(GLOB_PSIZE_2048, gregs + GLOB_PSIZE);
 
        /* All of memsize is given to bigmac. */
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size,
+       sbus_writel(resource_size(&qec_op->resource[1]),
                    gregs + GLOB_MSIZE);
 
        /* Half to the transmitter, half to the receiver. */
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+       sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
                    gregs + GLOB_TSIZE);
-       sbus_writel(qec_sdev->reg_addrs[1].reg_size >> 1,
+       sbus_writel(resource_size(&qec_op->resource[1]) >> 1,
                    gregs + GLOB_RSIZE);
 }
 
@@ -239,9 +240,10 @@ static void bigmac_init_rings(struct bigmac *bp, int from_irq)
                skb_reserve(skb, 34);
 
                bb->be_rxd[i].rx_addr =
-                       sbus_map_single(bp->bigmac_sdev, skb->data,
-                                       RX_BUF_ALLOC_SIZE - 34,
-                                       SBUS_DMA_FROMDEVICE);
+                       dma_map_single(&bp->bigmac_op->dev,
+                                      skb->data,
+                                      RX_BUF_ALLOC_SIZE - 34,
+                                      DMA_FROM_DEVICE);
                bb->be_rxd[i].rx_flags =
                        (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
        }
@@ -776,9 +778,9 @@ static void bigmac_tx(struct bigmac *bp)
                skb = bp->tx_skbs[elem];
                bp->enet_stats.tx_packets++;
                bp->enet_stats.tx_bytes += skb->len;
-               sbus_unmap_single(bp->bigmac_sdev,
-                                 this->tx_addr, skb->len,
-                                 SBUS_DMA_TODEVICE);
+               dma_unmap_single(&bp->bigmac_op->dev,
+                                this->tx_addr, skb->len,
+                                DMA_TO_DEVICE);
 
                DTX(("skb(%p) ", skb));
                bp->tx_skbs[elem] = NULL;
@@ -831,18 +833,19 @@ static void bigmac_rx(struct bigmac *bp)
                                drops++;
                                goto drop_it;
                        }
-                       sbus_unmap_single(bp->bigmac_sdev,
-                                         this->rx_addr,
-                                         RX_BUF_ALLOC_SIZE - 34,
-                                         SBUS_DMA_FROMDEVICE);
+                       dma_unmap_single(&bp->bigmac_op->dev,
+                                        this->rx_addr,
+                                        RX_BUF_ALLOC_SIZE - 34,
+                                        DMA_FROM_DEVICE);
                        bp->rx_skbs[elem] = new_skb;
                        new_skb->dev = bp->dev;
                        skb_put(new_skb, ETH_FRAME_LEN);
                        skb_reserve(new_skb, 34);
-                       this->rx_addr = sbus_map_single(bp->bigmac_sdev,
-                                                       new_skb->data,
-                                                       RX_BUF_ALLOC_SIZE - 34,
-                                                       SBUS_DMA_FROMDEVICE);
+                       this->rx_addr =
+                               dma_map_single(&bp->bigmac_op->dev,
+                                              new_skb->data,
+                                              RX_BUF_ALLOC_SIZE - 34,
+                                              DMA_FROM_DEVICE);
                        this->rx_flags =
                                (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH));
 
@@ -857,13 +860,13 @@ static void bigmac_rx(struct bigmac *bp)
                        }
                        skb_reserve(copy_skb, 2);
                        skb_put(copy_skb, len);
-                       sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
-                                                    this->rx_addr, len,
-                                                    SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(&bp->bigmac_op->dev,
+                                               this->rx_addr, len,
+                                               DMA_FROM_DEVICE);
                        skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
-                       sbus_dma_sync_single_for_device(bp->bigmac_sdev,
-                                                       this->rx_addr, len,
-                                                       SBUS_DMA_FROMDEVICE);
+                       dma_sync_single_for_device(&bp->bigmac_op->dev,
+                                                  this->rx_addr, len,
+                                                  DMA_FROM_DEVICE);
 
                        /* Reuse original ring buffer. */
                        this->rx_flags =
@@ -959,7 +962,8 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 mapping;
 
        len = skb->len;
-       mapping = sbus_map_single(bp->bigmac_sdev, skb->data, len, SBUS_DMA_TODEVICE);
+       mapping = dma_map_single(&bp->bigmac_op->dev, skb->data,
+                                len, DMA_TO_DEVICE);
 
        /* Avoid a race... */
        spin_lock_irq(&bp->lock);
@@ -1051,12 +1055,8 @@ static void bigmac_set_multicast(struct net_device *dev)
 /* Ethtool support... */
 static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct bigmac *bp = dev->priv;
-
        strcpy(info->driver, "sunbmac");
        strcpy(info->version, "2.0");
-       sprintf(info->bus_info, "SBUS:%d",
-               bp->qec_sdev->slot);
 }
 
 static u32 bigmac_get_link(struct net_device *dev)
@@ -1075,14 +1075,15 @@ static const struct ethtool_ops bigmac_ethtool_ops = {
        .get_link               = bigmac_get_link,
 };
 
-static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
+static int __devinit bigmac_ether_init(struct of_device *op,
+                                      struct of_device *qec_op)
 {
-       struct net_device *dev;
        static int version_printed;
-       struct bigmac *bp;
+       struct net_device *dev;
        u8 bsizes, bsizes_more;
-       int i;
        DECLARE_MAC_BUF(mac);
+       struct bigmac *bp;
+       int i;
 
        /* Get a new device struct for this interface. */
        dev = alloc_etherdev(sizeof(struct bigmac));
@@ -1092,32 +1093,21 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        if (version_printed++ == 0)
                printk(KERN_INFO "%s", version);
 
-       dev->base_addr = (long) qec_sdev;
        for (i = 0; i < 6; i++)
                dev->dev_addr[i] = idprom->id_ethaddr[i];
 
        /* Setup softc, with backpointers to QEC and BigMAC SBUS device structs. */
-       bp = dev->priv;
-       bp->qec_sdev = qec_sdev;
-       bp->bigmac_sdev = qec_sdev->child;
+       bp = netdev_priv(dev);
+       bp->qec_op = qec_op;
+       bp->bigmac_op = op;
 
-       SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        spin_lock_init(&bp->lock);
 
-       /* Verify the registers we expect, are actually there. */
-       if ((bp->bigmac_sdev->num_registers != 3) ||
-          (bp->qec_sdev->num_registers != 2)) {
-               printk(KERN_ERR "BIGMAC: Device does not have 2 and 3 regs, it has %d and %d.\n",
-                      bp->qec_sdev->num_registers,
-                      bp->bigmac_sdev->num_registers);
-               printk(KERN_ERR "BIGMAC: Would you like that for here or to go?\n");
-               goto fail_and_cleanup;
-       }
-
        /* Map in QEC global control registers. */
-       bp->gregs = sbus_ioremap(&bp->qec_sdev->resource[0], 0,
-                                GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
+       bp->gregs = of_ioremap(&qec_op->resource[0], 0,
+                              GLOB_REG_SIZE, "BigMAC QEC GLobal Regs");
        if (!bp->gregs) {
                printk(KERN_ERR "BIGMAC: Cannot map QEC global registers.\n");
                goto fail_and_cleanup;
@@ -1134,13 +1124,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
                goto fail_and_cleanup;
 
        /* Get supported SBUS burst sizes. */
-       bsizes = prom_getintdefault(bp->qec_sdev->prom_node,
-                                   "burst-sizes",
-                                   0xff);
-
-       bsizes_more = prom_getintdefault(bp->qec_sdev->bus->prom_node,
-                                        "burst-sizes",
-                                        0xff);
+       bsizes = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
+       bsizes_more = of_getintprop_default(qec_op->node, "burst-sizes", 0xff);
 
        bsizes &= 0xff;
        if (bsizes_more != 0xff)
@@ -1154,16 +1139,16 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        qec_init(bp);
 
        /* Map in the BigMAC channel registers. */
-       bp->creg = sbus_ioremap(&bp->bigmac_sdev->resource[0], 0,
-                               CREG_REG_SIZE, "BigMAC QEC Channel Regs");
+       bp->creg = of_ioremap(&op->resource[0], 0,
+                             CREG_REG_SIZE, "BigMAC QEC Channel Regs");
        if (!bp->creg) {
                printk(KERN_ERR "BIGMAC: Cannot map QEC channel registers.\n");
                goto fail_and_cleanup;
        }
 
        /* Map in the BigMAC control registers. */
-       bp->bregs = sbus_ioremap(&bp->bigmac_sdev->resource[1], 0,
-                                BMAC_REG_SIZE, "BigMAC Primary Regs");
+       bp->bregs = of_ioremap(&op->resource[1], 0,
+                              BMAC_REG_SIZE, "BigMAC Primary Regs");
        if (!bp->bregs) {
                printk(KERN_ERR "BIGMAC: Cannot map BigMAC primary registers.\n");
                goto fail_and_cleanup;
@@ -1172,8 +1157,8 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        /* Map in the BigMAC transceiver registers, this is how you poke at
         * the BigMAC's PHY.
         */
-       bp->tregs = sbus_ioremap(&bp->bigmac_sdev->resource[2], 0,
-                                TCVR_REG_SIZE, "BigMAC Transceiver Regs");
+       bp->tregs = of_ioremap(&op->resource[2], 0,
+                              TCVR_REG_SIZE, "BigMAC Transceiver Regs");
        if (!bp->tregs) {
                printk(KERN_ERR "BIGMAC: Cannot map BigMAC transceiver registers.\n");
                goto fail_and_cleanup;
@@ -1183,17 +1168,17 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        bigmac_stop(bp);
 
        /* Allocate transmit/receive descriptor DVMA block. */
-       bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev,
-                                              PAGE_SIZE,
-                                              &bp->bblock_dvma);
+       bp->bmac_block = dma_alloc_coherent(&bp->bigmac_op->dev,
+                                           PAGE_SIZE,
+                                           &bp->bblock_dvma, GFP_ATOMIC);
        if (bp->bmac_block == NULL || bp->bblock_dvma == 0) {
                printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n");
                goto fail_and_cleanup;
        }
 
        /* Get the board revision of this BigMAC. */
-       bp->board_rev = prom_getintdefault(bp->bigmac_sdev->prom_node,
-                                          "board-version", 1);
+       bp->board_rev = of_getintprop_default(bp->bigmac_op->node,
+                                             "board-version", 1);
 
        /* Init auto-negotiation timer state. */
        init_timer(&bp->bigmac_timer);
@@ -1217,7 +1202,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
        dev->watchdog_timeo = 5*HZ;
 
        /* Finish net device registration. */
-       dev->irq = bp->bigmac_sdev->irqs[0];
+       dev->irq = bp->bigmac_op->irqs[0];
        dev->dma = 0;
 
        if (register_netdev(dev)) {
@@ -1225,7 +1210,7 @@ static int __devinit bigmac_ether_init(struct sbus_dev *qec_sdev)
                goto fail_and_cleanup;
        }
 
-       dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
+       dev_set_drvdata(&bp->bigmac_op->dev, bp);
 
        printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
               dev->name, print_mac(mac, dev->dev_addr));
@@ -1236,66 +1221,67 @@ fail_and_cleanup:
        /* Something went wrong, undo whatever we did so far. */
        /* Free register mappings if any. */
        if (bp->gregs)
-               sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+               of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
        if (bp->creg)
-               sbus_iounmap(bp->creg, CREG_REG_SIZE);
+               of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
        if (bp->bregs)
-               sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+               of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
        if (bp->tregs)
-               sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+               of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
 
        if (bp->bmac_block)
-               sbus_free_consistent(bp->bigmac_sdev,
-                                    PAGE_SIZE,
-                                    bp->bmac_block,
-                                    bp->bblock_dvma);
+               dma_free_coherent(&bp->bigmac_op->dev,
+                                 PAGE_SIZE,
+                                 bp->bmac_block,
+                                 bp->bblock_dvma);
 
        /* This also frees the co-located 'dev->priv' */
        free_netdev(dev);
        return -ENODEV;
 }
 
-/* QEC can be the parent of either QuadEthernet or
- * a BigMAC.  We want the latter.
+/* QEC can be the parent of either QuadEthernet or a BigMAC.  We want
+ * the latter.
  */
-static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit bigmac_sbus_probe(struct of_device *op,
+                                      const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device *parent = op->dev.parent;
+       struct of_device *qec_op;
 
-       if (!strcmp(dp->name, "be"))
-               sdev = sdev->parent;
+       qec_op = to_of_device(parent);
 
-       return bigmac_ether_init(sdev);
+       return bigmac_ether_init(op, qec_op);
 }
 
-static int __devexit bigmac_sbus_remove(struct of_device *dev)
+static int __devexit bigmac_sbus_remove(struct of_device *op)
 {
-       struct bigmac *bp = dev_get_drvdata(&dev->dev);
+       struct bigmac *bp = dev_get_drvdata(&op->dev);
+       struct device *parent = op->dev.parent;
        struct net_device *net_dev = bp->dev;
+       struct of_device *qec_op;
+
+       qec_op = to_of_device(parent);
 
        unregister_netdev(net_dev);
 
-       sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
-       sbus_iounmap(bp->creg, CREG_REG_SIZE);
-       sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
-       sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
-       sbus_free_consistent(bp->bigmac_sdev,
-                            PAGE_SIZE,
-                            bp->bmac_block,
-                            bp->bblock_dvma);
+       of_iounmap(&qec_op->resource[0], bp->gregs, GLOB_REG_SIZE);
+       of_iounmap(&op->resource[0], bp->creg, CREG_REG_SIZE);
+       of_iounmap(&op->resource[1], bp->bregs, BMAC_REG_SIZE);
+       of_iounmap(&op->resource[2], bp->tregs, TCVR_REG_SIZE);
+       dma_free_coherent(&op->dev,
+                         PAGE_SIZE,
+                         bp->bmac_block,
+                         bp->bblock_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id bigmac_sbus_match[] = {
-       {
-               .name = "qec",
-       },
+static const struct of_device_id bigmac_sbus_match[] = {
        {
                .name = "be",
        },
@@ -1313,7 +1299,7 @@ static struct of_platform_driver bigmac_sbus_driver = {
 
 static int __init bigmac_init(void)
 {
-       return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&bigmac_sbus_driver, &of_bus_type);
 }
 
 static void __exit bigmac_exit(void)
index b563d3c2993e832263dca9f341e86ba765067309..8840bc0b840b34e6e34817f3f9dc0d9d3b6d9ffa 100644 (file)
@@ -329,8 +329,8 @@ struct bigmac {
        unsigned int            timer_ticks;
 
        struct net_device_stats enet_stats;
-       struct sbus_dev         *qec_sdev;
-       struct sbus_dev         *bigmac_sdev;
+       struct of_device        *qec_op;
+       struct of_device        *bigmac_op;
        struct net_device       *dev;
 };
 
index b79d5f018f798abf59f7822b9def0a483b143cb6..f1ebeb5f65b2f56d6ba3a6ee9da9eb579cfb16d1 100644 (file)
@@ -3,7 +3,7 @@
  *           "Happy Meal Ethernet" found on SunSwift SBUS cards.
  *
  * Copyright (C) 1996, 1998, 1999, 2002, 2003,
               2006 David S. Miller (davem@davemloft.net)
*             2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * Changes :
  * 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -34,6 +34,7 @@
 #include <linux/skbuff.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -41,8 +42,9 @@
 #include <asm/byteorder.h>
 
 #ifdef CONFIG_SPARC
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/prom.h>
@@ -60,8 +62,8 @@
 #include "sunhme.h"
 
 #define DRV_NAME       "sunhme"
-#define DRV_VERSION    "3.00"
-#define DRV_RELDATE    "June 23, 2006"
+#define DRV_VERSION    "3.10"
+#define DRV_RELDATE    "August 26, 2008"
 #define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -251,13 +253,13 @@ static u32 pci_hme_read_desc32(hme32 *p)
 #define hme_read_desc32(__hp, __p) \
        ((__hp)->read_desc32(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir)))
+       ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir)))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)))
+       ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)))
 #else
 #ifdef CONFIG_SBUS
 /* SBUS only compilation */
@@ -277,13 +279,13 @@ do {      (__txd)->tx_addr = (__force hme32)(u32)(__addr); \
 } while(0)
 #define hme_read_desc32(__hp, __p)     ((__force u32)(hme32)*(__p))
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+       dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+       dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #else
 /* PCI only compilation */
 #define hme_write32(__hp, __reg, __val) \
@@ -305,36 +307,17 @@ static inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p)
        return le32_to_cpup((__le32 *)p);
 }
 #define hme_dma_map(__hp, __ptr, __size, __dir) \
-       pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir))
+       pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir))
 #define hme_dma_unmap(__hp, __addr, __size, __dir) \
-       pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \
-       pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))
 #define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \
-       pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))
+       pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))
 #endif
 #endif
 
 
-#ifdef SBUS_DMA_BIDIRECTIONAL
-#      define DMA_BIDIRECTIONAL        SBUS_DMA_BIDIRECTIONAL
-#else
-#      define DMA_BIDIRECTIONAL        0
-#endif
-
-#ifdef SBUS_DMA_FROMDEVICE
-#      define DMA_FROMDEVICE           SBUS_DMA_FROMDEVICE
-#else
-#      define DMA_TODEVICE             1
-#endif
-
-#ifdef SBUS_DMA_TODEVICE
-#      define DMA_TODEVICE             SBUS_DMA_TODEVICE
-#else
-#      define DMA_FROMDEVICE           2
-#endif
-
-
 /* Oh yes, the MIF BitBang is mighty fun to program.  BitBucket is more like it. */
 static void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit)
 {
@@ -1224,7 +1207,8 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
 
                        rxd = &hp->happy_block->happy_meal_rxd[i];
                        dma_addr = hme_read_desc32(hp, &rxd->rx_addr);
-                       hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr,
+                                        RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
                        dev_kfree_skb_any(skb);
                        hp->rx_skbs[i] = NULL;
                }
@@ -1242,10 +1226,10 @@ static void happy_meal_clean_rings(struct happy_meal *hp)
                        for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
                                txd = &hp->happy_block->happy_meal_txd[i];
                                dma_addr = hme_read_desc32(hp, &txd->tx_addr);
-                               hme_dma_unmap(hp, dma_addr,
-                                             (hme_read_desc32(hp, &txd->tx_flags)
-                                              & TXFLAG_SIZE),
-                                             DMA_TODEVICE);
+                               dma_unmap_single(hp->dma_dev, dma_addr,
+                                                (hme_read_desc32(hp, &txd->tx_flags)
+                                                 & TXFLAG_SIZE),
+                                                DMA_TO_DEVICE);
 
                                if (frag != skb_shinfo(skb)->nr_frags)
                                        i++;
@@ -1287,7 +1271,8 @@ static void happy_meal_init_rings(struct happy_meal *hp)
                skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
                hme_write_rxd(hp, &hb->happy_meal_rxd[i],
                              (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)),
-                             hme_dma_map(hp, skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+                             dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE,
+                                            DMA_FROM_DEVICE));
                skb_reserve(skb, RX_OFFSET);
        }
 
@@ -1593,7 +1578,7 @@ static int happy_meal_init(struct happy_meal *hp)
        if ((hp->happy_bursts & DMA_BURST64) &&
            ((hp->happy_flags & HFLAG_PCI) != 0
 #ifdef CONFIG_SBUS
-            || sbus_can_burst64(hp->happy_dev)
+            || sbus_can_burst64()
 #endif
             || 0)) {
                u32 gcfg = GREG_CFG_BURST64;
@@ -1603,11 +1588,13 @@ static int happy_meal_init(struct happy_meal *hp)
                 * do not.  -DaveM
                 */
 #ifdef CONFIG_SBUS
-               if ((hp->happy_flags & HFLAG_PCI) == 0 &&
-                   sbus_can_dma_64bit(hp->happy_dev)) {
-                       sbus_set_sbus64(hp->happy_dev,
-                                       hp->happy_bursts);
-                       gcfg |= GREG_CFG_64BIT;
+               if ((hp->happy_flags & HFLAG_PCI) == 0) {
+                       struct of_device *op = hp->happy_dev;
+                       if (sbus_can_dma_64bit()) {
+                               sbus_set_sbus64(&op->dev,
+                                               hp->happy_bursts);
+                               gcfg |= GREG_CFG_64BIT;
+                       }
                }
 #endif
 
@@ -1966,7 +1953,7 @@ static void happy_meal_tx(struct happy_meal *hp)
                        dma_len = hme_read_desc32(hp, &this->tx_flags);
 
                        dma_len &= TXFLAG_SIZE;
-                       hme_dma_unmap(hp, dma_addr, dma_len, DMA_TODEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE);
 
                        elem = NEXT_TX(elem);
                        this = &txbase[elem];
@@ -2044,13 +2031,14 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
                                drops++;
                                goto drop_it;
                        }
-                       hme_dma_unmap(hp, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE);
+                       dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE);
                        hp->rx_skbs[elem] = new_skb;
                        new_skb->dev = dev;
                        skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4));
                        hme_write_rxd(hp, this,
                                      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
-                                     hme_dma_map(hp, new_skb->data, RX_BUF_ALLOC_SIZE, DMA_FROMDEVICE));
+                                     dma_map_single(hp->dma_dev, new_skb->data, RX_BUF_ALLOC_SIZE,
+                                                    DMA_FROM_DEVICE));
                        skb_reserve(new_skb, RX_OFFSET);
 
                        /* Trim the original skb for the netif. */
@@ -2065,10 +2053,9 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
 
                        skb_reserve(copy_skb, 2);
                        skb_put(copy_skb, len);
-                       hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE);
+                       dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
                        skb_copy_from_linear_data(skb, copy_skb->data, len);
-                       hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE);
-
+                       dma_sync_single_for_device(hp->dma_dev, dma_addr, len, DMA_FROM_DEVICE);
                        /* Reuse original ring buffer. */
                        hme_write_rxd(hp, this,
                                      (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)),
@@ -2300,7 +2287,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                u32 mapping, len;
 
                len = skb->len;
-               mapping = hme_dma_map(hp, skb->data, len, DMA_TODEVICE);
+               mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE);
                tx_flags |= (TXFLAG_SOP | TXFLAG_EOP);
                hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry],
                              (tx_flags | (len & TXFLAG_SIZE)),
@@ -2314,7 +2301,8 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                 * Otherwise we could race with the device.
                 */
                first_len = skb_headlen(skb);
-               first_mapping = hme_dma_map(hp, skb->data, first_len, DMA_TODEVICE);
+               first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len,
+                                              DMA_TO_DEVICE);
                entry = NEXT_TX(entry);
 
                for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -2322,10 +2310,9 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        u32 len, mapping, this_txflags;
 
                        len = this_frag->size;
-                       mapping = hme_dma_map(hp,
-                                             ((void *) page_address(this_frag->page) +
-                                              this_frag->page_offset),
-                                             len, DMA_TODEVICE);
+                       mapping = dma_map_page(hp->dma_dev, this_frag->page,
+                                              this_frag->page_offset, len,
+                                              DMA_TO_DEVICE);
                        this_txflags = tx_flags;
                        if (frag == skb_shinfo(skb)->nr_frags - 1)
                                this_txflags |= TXFLAG_EOP;
@@ -2493,9 +2480,12 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
        }
 #ifdef CONFIG_SBUS
        else {
-               struct sbus_dev *sdev = hp->happy_dev;
-               sprintf(info->bus_info, "SBUS:%d",
-                       sdev->slot);
+               const struct linux_prom_registers *regs;
+               struct of_device *op = hp->happy_dev;
+               regs = of_get_property(op->node, "regs", NULL);
+               if (regs)
+                       sprintf(info->bus_info, "SBUS:%d",
+                               regs->which_io);
        }
 #endif
 }
@@ -2521,63 +2511,21 @@ static const struct ethtool_ops hme_ethtool_ops = {
 static int hme_version_printed;
 
 #ifdef CONFIG_SBUS
-void __devinit quattro_get_ranges(struct quattro *qp)
-{
-       struct sbus_dev *sdev = qp->quattro_dev;
-       int err;
-
-       err = prom_getproperty(sdev->prom_node,
-                              "ranges",
-                              (char *)&qp->ranges[0],
-                              sizeof(qp->ranges));
-       if (err == 0 || err == -1) {
-               qp->nranges = 0;
-               return;
-       }
-       qp->nranges = (err / sizeof(struct linux_prom_ranges));
-}
-
-static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
-{
-       struct sbus_dev *sdev = hp->happy_dev;
-       int rng;
-
-       for (rng = 0; rng < qp->nranges; rng++) {
-               struct linux_prom_ranges *rngp = &qp->ranges[rng];
-               int reg;
-
-               for (reg = 0; reg < 5; reg++) {
-                       if (sdev->reg_addrs[reg].which_io ==
-                           rngp->ot_child_space)
-                               break;
-               }
-               if (reg == 5)
-                       continue;
-
-               sdev->reg_addrs[reg].which_io = rngp->ot_parent_space;
-               sdev->reg_addrs[reg].phys_addr += rngp->ot_parent_base;
-       }
-}
-
 /* Given a happy meal sbus device, find it's quattro parent.
  * If none exist, allocate and return a new one.
  *
  * Return NULL on failure.
  */
-static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct of_device *child)
 {
-       struct sbus_dev *sdev;
+       struct device *parent = child->dev.parent;
+       struct of_device *op;
        struct quattro *qp;
-       int i;
 
-       for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               for (i = 0, sdev = qp->quattro_dev;
-                    (sdev != NULL) && (i < 4);
-                    sdev = sdev->next, i++) {
-                       if (sdev == goal_sdev)
-                               return qp;
-               }
-       }
+       op = to_of_device(parent);
+       qp = dev_get_drvdata(&op->dev);
+       if (qp)
+               return qp;
 
        qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
        if (qp != NULL) {
@@ -2586,10 +2534,11 @@ static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
                for (i = 0; i < 4; i++)
                        qp->happy_meals[i] = NULL;
 
-               qp->quattro_dev = goal_sdev;
+               qp->quattro_dev = child;
                qp->next = qfe_sbus_list;
                qfe_sbus_list = qp;
-               quattro_get_ranges(qp);
+
+               dev_set_drvdata(&op->dev, qp);
        }
        return qp;
 }
@@ -2602,10 +2551,10 @@ static void __init quattro_sbus_register_irqs(void)
        struct quattro *qp;
 
        for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               struct sbus_dev *sdev = qp->quattro_dev;
+               struct of_device *op = qp->quattro_dev;
                int err;
 
-               err = request_irq(sdev->irqs[0],
+               err = request_irq(op->irqs[0],
                                  quattro_sbus_interrupt,
                                  IRQF_SHARED, "Quattro",
                                  qp);
@@ -2621,9 +2570,9 @@ static void quattro_sbus_free_irqs(void)
        struct quattro *qp;
 
        for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
-               struct sbus_dev *sdev = qp->quattro_dev;
+               struct of_device *op = qp->quattro_dev;
 
-               free_irq(sdev->irqs[0], qp);
+               free_irq(op->irqs[0], qp);
        }
 }
 #endif /* CONFIG_SBUS */
@@ -2660,9 +2609,9 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev)
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_SBUS
-static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe)
 {
-       struct device_node *dp = sdev->ofdev.node;
+       struct device_node *dp = op->node, *sbus_dp;
        struct quattro *qp = NULL;
        struct happy_meal *hp;
        struct net_device *dev;
@@ -2671,7 +2620,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        DECLARE_MAC_BUF(mac);
 
        if (is_qfe) {
-               qp = quattro_sbus_find(sdev);
+               qp = quattro_sbus_find(op);
                if (qp == NULL)
                        goto err_out;
                for (qfe_slot = 0; qfe_slot < 4; qfe_slot++)
@@ -2685,7 +2634,7 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        dev = alloc_etherdev(sizeof(struct happy_meal));
        if (!dev)
                goto err_out;
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        if (hme_version_printed++ == 0)
                printk(KERN_INFO "%s", version);
@@ -2713,56 +2662,50 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
                        memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
        }
 
-       hp = dev->priv;
+       hp = netdev_priv(dev);
 
-       hp->happy_dev = sdev;
+       hp->happy_dev = op;
+       hp->dma_dev = &op->dev;
 
        spin_lock_init(&hp->happy_lock);
 
        err = -ENODEV;
-       if (sdev->num_registers != 5) {
-               printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
-                      sdev->num_registers);
-               goto err_out_free_netdev;
-       }
-
        if (qp != NULL) {
                hp->qfe_parent = qp;
                hp->qfe_ent = qfe_slot;
                qp->happy_meals[qfe_slot] = dev;
-               quattro_apply_ranges(qp, hp);
        }
 
-       hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
-                                GREG_REG_SIZE, "HME Global Regs");
+       hp->gregs = of_ioremap(&op->resource[0], 0,
+                              GREG_REG_SIZE, "HME Global Regs");
        if (!hp->gregs) {
                printk(KERN_ERR "happymeal: Cannot map global registers.\n");
                goto err_out_free_netdev;
        }
 
-       hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
-                                  ETX_REG_SIZE, "HME TX Regs");
+       hp->etxregs = of_ioremap(&op->resource[1], 0,
+                                ETX_REG_SIZE, "HME TX Regs");
        if (!hp->etxregs) {
                printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
-                                  ERX_REG_SIZE, "HME RX Regs");
+       hp->erxregs = of_ioremap(&op->resource[2], 0,
+                                ERX_REG_SIZE, "HME RX Regs");
        if (!hp->erxregs) {
                printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
-                                     BMAC_REG_SIZE, "HME BIGMAC Regs");
+       hp->bigmacregs = of_ioremap(&op->resource[3], 0,
+                                   BMAC_REG_SIZE, "HME BIGMAC Regs");
        if (!hp->bigmacregs) {
                printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
                goto err_out_iounmap;
        }
 
-       hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
-                                  TCVR_REG_SIZE, "HME Tranceiver Regs");
+       hp->tcvregs = of_ioremap(&op->resource[4], 0,
+                                TCVR_REG_SIZE, "HME Tranceiver Regs");
        if (!hp->tcvregs) {
                printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
                goto err_out_iounmap;
@@ -2781,13 +2724,18 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        if (qp != NULL)
                hp->happy_flags |= HFLAG_QUATTRO;
 
+       sbus_dp = to_of_device(op->dev.parent)->node;
+       if (is_qfe)
+               sbus_dp = to_of_device(op->dev.parent->parent)->node;
+
        /* Get the supported DVMA burst sizes from our Happy SBUS. */
-       hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+       hp->happy_bursts = of_getintprop_default(sbus_dp,
                                                 "burst-sizes", 0x00);
 
-       hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
-                                               PAGE_SIZE,
-                                               &hp->hblock_dvma);
+       hp->happy_block = dma_alloc_coherent(hp->dma_dev,
+                                            PAGE_SIZE,
+                                            &hp->hblock_dvma,
+                                            GFP_ATOMIC);
        err = -ENOMEM;
        if (!hp->happy_block) {
                printk(KERN_ERR "happymeal: Cannot allocate descriptors.\n");
@@ -2816,19 +2764,13 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        /* Happy Meal can do it all... */
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-       /* Hook up PCI register/dma accessors. */
+       /* Hook up SBUS register/descriptor accessors. */
        hp->read_desc32 = sbus_hme_read_desc32;
        hp->write_txd = sbus_hme_write_txd;
        hp->write_rxd = sbus_hme_write_rxd;
-       hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single;
-       hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single;
-       hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-               sbus_dma_sync_single_for_cpu;
-       hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-               sbus_dma_sync_single_for_device;
        hp->read32 = sbus_hme_read32;
        hp->write32 = sbus_hme_write32;
 #endif
@@ -2843,10 +2785,10 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
        if (register_netdev(hp->dev)) {
                printk(KERN_ERR "happymeal: Cannot register net device, "
                       "aborting.\n");
-               goto err_out_free_consistent;
+               goto err_out_free_coherent;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, hp);
+       dev_set_drvdata(&op->dev, hp);
 
        if (qfe_slot != -1)
                printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
@@ -2859,23 +2801,23 @@ static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe
 
        return 0;
 
-err_out_free_consistent:
-       sbus_free_consistent(hp->happy_dev,
-                            PAGE_SIZE,
-                            hp->happy_block,
-                            hp->hblock_dvma);
+err_out_free_coherent:
+       dma_free_coherent(hp->dma_dev,
+                         PAGE_SIZE,
+                         hp->happy_block,
+                         hp->hblock_dvma);
 
 err_out_iounmap:
        if (hp->gregs)
-               sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+               of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
        if (hp->etxregs)
-               sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+               of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
        if (hp->erxregs)
-               sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+               of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
        if (hp->bigmacregs)
-               sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+               of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
        if (hp->tcvregs)
-               sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+               of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
 
 err_out_free_netdev:
        free_netdev(dev);
@@ -3035,6 +2977,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        memset(hp, 0, sizeof(*hp));
 
        hp->happy_dev = pdev;
+       hp->dma_dev = &pdev->dev;
 
        spin_lock_init(&hp->happy_lock);
 
@@ -3121,7 +3064,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
 #endif
 
        hp->happy_block = (struct hmeal_init_block *)
-               pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma);
+               dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &hp->hblock_dvma, GFP_KERNEL);
 
        err = -ENODEV;
        if (!hp->happy_block) {
@@ -3151,16 +3094,10 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
        dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
 
 #if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
-       /* Hook up PCI register/dma accessors. */
+       /* Hook up PCI register/descriptor accessors. */
        hp->read_desc32 = pci_hme_read_desc32;
        hp->write_txd = pci_hme_write_txd;
        hp->write_rxd = pci_hme_write_rxd;
-       hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single;
-       hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single;
-       hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int))
-               pci_dma_sync_single_for_cpu;
-       hp->dma_sync_for_device = (void (*)(void *, u32, long, int))
-               pci_dma_sync_single_for_device;
        hp->read32 = pci_hme_read32;
        hp->write32 = pci_hme_write32;
 #endif
@@ -3231,10 +3168,8 @@ static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
 
        unregister_netdev(net_dev);
 
-       pci_free_consistent(hp->happy_dev,
-                           PAGE_SIZE,
-                           hp->happy_block,
-                           hp->hblock_dvma);
+       dma_free_coherent(hp->dma_dev, PAGE_SIZE,
+                         hp->happy_block, hp->hblock_dvma);
        iounmap(hp->gregs);
        pci_release_regions(hp->happy_dev);
 
@@ -3279,46 +3214,45 @@ static void happy_meal_pci_exit(void)
 #endif
 
 #ifdef CONFIG_SBUS
-static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit hme_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
+       struct device_node *dp = op->node;
        const char *model = of_get_property(dp, "model", NULL);
        int is_qfe = (match->data != NULL);
 
        if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
                is_qfe = 1;
 
-       return happy_meal_sbus_probe_one(sdev, is_qfe);
+       return happy_meal_sbus_probe_one(op, is_qfe);
 }
 
-static int __devexit hme_sbus_remove(struct of_device *dev)
+static int __devexit hme_sbus_remove(struct of_device *op)
 {
-       struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+       struct happy_meal *hp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = hp->dev;
 
        unregister_netdev(net_dev);
 
        /* XXX qfe parent interrupt... */
 
-       sbus_iounmap(hp->gregs, GREG_REG_SIZE);
-       sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
-       sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
-       sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
-       sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
-       sbus_free_consistent(hp->happy_dev,
-                            PAGE_SIZE,
-                            hp->happy_block,
-                            hp->hblock_dvma);
+       of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE);
+       of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE);
+       of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE);
+       of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE);
+       of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE);
+       dma_free_coherent(hp->dma_dev,
+                         PAGE_SIZE,
+                         hp->happy_block,
+                         hp->hblock_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id hme_sbus_match[] = {
+static const struct of_device_id hme_sbus_match[] = {
        {
                .name = "SUNW,hme",
        },
@@ -3346,7 +3280,7 @@ static int __init happy_meal_sbus_init(void)
 {
        int err;
 
-       err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+       err = of_register_driver(&hme_sbus_driver, &of_bus_type);
        if (!err)
                quattro_sbus_register_irqs();
 
index 4da5539fac7b3032f4b1f911a06705cfd2ca0132..efd2ca0fcad30d85362d9f0d1e2412ab49b5e7fc 100644 (file)
@@ -405,14 +405,11 @@ struct happy_meal {
        u32 (*read_desc32)(hme32 *);
        void (*write_txd)(struct happy_meal_txd *, u32, u32);
        void (*write_rxd)(struct happy_meal_rxd *, u32, u32);
-       u32 (*dma_map)(void *, void *, long, int);
-       void (*dma_unmap)(void *, u32, long, int);
-       void (*dma_sync_for_cpu)(void *, u32, long, int);
-       void (*dma_sync_for_device)(void *, u32, long, int);
 #endif
 
-       /* This is either a sbus_dev or a pci_dev. */
+       /* This is either an of_device or a pci_dev. */
        void                      *happy_dev;
+       struct device             *dma_dev;
 
        spinlock_t                happy_lock;
 
index 4e994f87469e4e9fc98ecec83a734c3778cc8c38..704301a5a7ffed417655912cbc0a61552d55bf71 100644 (file)
@@ -91,6 +91,9 @@ static char lancestr[] = "LANCE";
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -98,7 +101,6 @@ static char lancestr[] = "LANCE";
 #include <asm/pgtable.h>
 #include <asm/byteorder.h>     /* Used by the checksum routines */
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 #include <asm/auxio.h>         /* For tpe-link-test? setting */
 #include <asm/irq.h>
@@ -248,7 +250,7 @@ struct lance_private {
        int             rx_new, tx_new;
        int             rx_old, tx_old;
 
-       struct sbus_dma *ledma; /* If set this points to ledma  */
+       struct of_device *ledma;        /* If set this points to ledma  */
        char            tpe;            /* cable-selection is TPE       */
        char            auto_select;    /* cable-selection by carrier   */
        char            burst_sizes;    /* ledma SBus burst sizes       */
@@ -263,7 +265,8 @@ struct lance_private {
        char                   *name;
        dma_addr_t              init_block_dvma;
        struct net_device      *dev;              /* Backpointer        */
-       struct sbus_dev        *sdev;
+       struct of_device       *op;
+       struct of_device       *lebuffer;
        struct timer_list       multicast_timer;
 };
 
@@ -1272,27 +1275,29 @@ static void lance_set_multicast_retry(unsigned long _opaque)
 static void lance_free_hwresources(struct lance_private *lp)
 {
        if (lp->lregs)
-               sbus_iounmap(lp->lregs, LANCE_REG_SIZE);
+               of_iounmap(&lp->op->resource[0], lp->lregs, LANCE_REG_SIZE);
+       if (lp->dregs) {
+               struct of_device *ledma = lp->ledma;
+
+               of_iounmap(&ledma->resource[0], lp->dregs,
+                          resource_size(&ledma->resource[0]));
+       }
        if (lp->init_block_iomem) {
-               sbus_iounmap(lp->init_block_iomem,
-                            sizeof(struct lance_init_block));
+               of_iounmap(&lp->lebuffer->resource[0], lp->init_block_iomem,
+                          sizeof(struct lance_init_block));
        } else if (lp->init_block_mem) {
-               sbus_free_consistent(lp->sdev,
-                                    sizeof(struct lance_init_block),
-                                    lp->init_block_mem,
-                                    lp->init_block_dvma);
+               dma_free_coherent(&lp->op->dev,
+                                 sizeof(struct lance_init_block),
+                                 lp->init_block_mem,
+                                 lp->init_block_dvma);
        }
 }
 
 /* Ethtool support... */
 static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-       struct lance_private *lp = netdev_priv(dev);
-
        strcpy(info->driver, "sunlance");
        strcpy(info->version, "2.02");
-       sprintf(info->bus_info, "SBUS:%d",
-               lp->sdev->slot);
 }
 
 static u32 sparc_lance_get_link(struct net_device *dev)
@@ -1308,16 +1313,16 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = {
        .get_link               = sparc_lance_get_link,
 };
 
-static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
-                                          struct sbus_dma *ledma,
-                                          struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct of_device *op,
+                                          struct of_device *ledma,
+                                          struct of_device *lebuffer)
 {
+       struct device_node *dp = op->node;
        static unsigned version_printed;
-       struct device_node *dp = sdev->ofdev.node;
-       struct net_device *dev;
        struct lance_private *lp;
-       int    i;
+       struct net_device *dev;
        DECLARE_MAC_BUF(mac);
+       int    i;
 
        dev = alloc_etherdev(sizeof(struct lance_private) + 8);
        if (!dev)
@@ -1338,14 +1343,27 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                dev->dev_addr[i] = idprom->id_ethaddr[i];
 
        /* Get the IO region */
-       lp->lregs = sbus_ioremap(&sdev->resource[0], 0,
-                                LANCE_REG_SIZE, lancestr);
+       lp->lregs = of_ioremap(&op->resource[0], 0,
+                              LANCE_REG_SIZE, lancestr);
        if (!lp->lregs) {
                printk(KERN_ERR "SunLance: Cannot map registers.\n");
                goto fail;
        }
 
-       lp->sdev = sdev;
+       lp->ledma = ledma;
+       if (lp->ledma) {
+               lp->dregs = of_ioremap(&ledma->resource[0], 0,
+                                      resource_size(&ledma->resource[0]),
+                                      "ledma");
+               if (!lp->dregs) {
+                       printk(KERN_ERR "SunLance: Cannot map "
+                              "ledma registers.\n");
+                       goto fail;
+               }
+       }
+
+       lp->op = op;
+       lp->lebuffer = lebuffer;
        if (lebuffer) {
                /* sanity check */
                if (lebuffer->resource[0].start & 7) {
@@ -1353,8 +1371,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                        goto fail;
                }
                lp->init_block_iomem =
-                       sbus_ioremap(&lebuffer->resource[0], 0,
-                                    sizeof(struct lance_init_block), "lebuffer");
+                       of_ioremap(&lebuffer->resource[0], 0,
+                                  sizeof(struct lance_init_block), "lebuffer");
                if (!lp->init_block_iomem) {
                        printk(KERN_ERR "SunLance: Cannot map PIO buffer.\n");
                        goto fail;
@@ -1366,9 +1384,10 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                lp->tx = lance_tx_pio;
        } else {
                lp->init_block_mem =
-                       sbus_alloc_consistent(sdev, sizeof(struct lance_init_block),
-                                             &lp->init_block_dvma);
-               if (!lp->init_block_mem || lp->init_block_dvma == 0) {
+                       dma_alloc_coherent(&op->dev,
+                                          sizeof(struct lance_init_block),
+                                          &lp->init_block_dvma, GFP_ATOMIC);
+               if (!lp->init_block_mem) {
                        printk(KERN_ERR "SunLance: Cannot allocate consistent DMA memory.\n");
                        goto fail;
                }
@@ -1383,13 +1402,13 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                                                      LE_C3_BCON));
 
        lp->name = lancestr;
-       lp->ledma = ledma;
 
        lp->burst_sizes = 0;
        if (lp->ledma) {
-               struct device_node *ledma_dp = ledma->sdev->ofdev.node;
-               const char *prop;
+               struct device_node *ledma_dp = ledma->node;
+               struct device_node *sbus_dp;
                unsigned int sbmask;
+               const char *prop;
                u32 csr;
 
                /* Find burst-size property for ledma */
@@ -1397,7 +1416,8 @@ static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
                                                        "burst-sizes", 0);
 
                /* ledma may be capable of fast bursts, but sbus may not. */
-               sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+               sbus_dp = ledma_dp->parent;
+               sbmask = of_getintprop_default(sbus_dp, "burst-sizes",
                                               DMA_BURSTBITS);
                lp->burst_sizes &= sbmask;
 
@@ -1435,8 +1455,6 @@ no_link_test:
                        lp->tpe = 1;
                }
 
-               lp->dregs = ledma->regs;
-
                /* Reset ledma */
                csr = sbus_readl(lp->dregs + DMA_CSR);
                sbus_writel(csr | DMA_RST_ENET, lp->dregs + DMA_CSR);
@@ -1446,7 +1464,7 @@ no_link_test:
                lp->dregs = NULL;
 
        lp->dev = dev;
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
        dev->open = &lance_open;
        dev->stop = &lance_close;
        dev->hard_start_xmit = &lance_start_xmit;
@@ -1455,9 +1473,7 @@ no_link_test:
        dev->set_multicast_list = &lance_set_multicast;
        dev->ethtool_ops = &sparc_lance_ethtool_ops;
 
-       dev->irq = sdev->irqs[0];
-
-       dev->dma = 0;
+       dev->irq = op->irqs[0];
 
        /* We cannot sleep if the chip is busy during a
         * multicast list update event, because such events
@@ -1473,7 +1489,7 @@ no_link_test:
                goto fail;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, lp);
+       dev_set_drvdata(&op->dev, lp);
 
        printk(KERN_INFO "%s: LANCE %s\n",
               dev->name, print_mac(mac, dev->dev_addr));
@@ -1486,80 +1502,25 @@ fail:
        return -ENODEV;
 }
 
-/* On 4m, find the associated dma for the lance chip */
-static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
-{
-       struct sbus_dma *p;
-
-       for_each_dvma(p) {
-               if (p->sdev == sdev)
-                       return p;
-       }
-       return NULL;
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-#include <asm/machines.h>
-
-/* Find all the lance cards on the system and initialize them */
-static struct sbus_dev sun4_sdev;
-static int __devinit sparc_lance_init(void)
-{
-       if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
-           (idprom->id_machtype == (SM_SUN4|SM_4_470))) {
-               memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
-               sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
-               sun4_sdev.irqs[0] = 6;
-               return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
-       }
-       return -ENODEV;
-}
-
-static int __exit sunlance_sun4_remove(void)
+static int __devinit sunlance_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
-       struct net_device *net_dev = lp->dev;
-
-       unregister_netdev(net_dev);
-
-       lance_free_hwresources(lp);
-
-       free_netdev(net_dev);
-
-       dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
-
-       return 0;
-}
-
-#else /* !CONFIG_SUN4 */
-
-static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+       struct of_device *parent = to_of_device(op->dev.parent);
+       struct device_node *parent_dp = parent->node;
        int err;
 
-       if (sdev->parent) {
-               struct of_device *parent = &sdev->parent->ofdev;
-
-               if (!strcmp(parent->node->name, "ledma")) {
-                       struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
-
-                       err = sparc_lance_probe_one(sdev, ledma, NULL);
-               } else if (!strcmp(parent->node->name, "lebuffer")) {
-                       err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
-               } else
-                       err = sparc_lance_probe_one(sdev, NULL, NULL);
+       if (!strcmp(parent_dp->name, "ledma")) {
+               err = sparc_lance_probe_one(op, parent, NULL);
+       } else if (!strcmp(parent_dp->name, "lebuffer")) {
+               err = sparc_lance_probe_one(op, NULL, parent);
        } else
-               err = sparc_lance_probe_one(sdev, NULL, NULL);
+               err = sparc_lance_probe_one(op, NULL, NULL);
 
        return err;
 }
 
-static int __devexit sunlance_sbus_remove(struct of_device *dev)
+static int __devexit sunlance_sbus_remove(struct of_device *op)
 {
-       struct lance_private *lp = dev_get_drvdata(&dev->dev);
+       struct lance_private *lp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = lp->dev;
 
        unregister_netdev(net_dev);
@@ -1568,12 +1529,12 @@ static int __devexit sunlance_sbus_remove(struct of_device *dev)
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id sunlance_sbus_match[] = {
+static const struct of_device_id sunlance_sbus_match[] = {
        {
                .name = "le",
        },
@@ -1593,17 +1554,12 @@ static struct of_platform_driver sunlance_sbus_driver = {
 /* Find all the lance cards on the system and initialize them */
 static int __init sparc_lance_init(void)
 {
-       return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&sunlance_sbus_driver, &of_bus_type);
 }
-#endif /* !CONFIG_SUN4 */
 
 static void __exit sparc_lance_exit(void)
 {
-#ifdef CONFIG_SUN4
-       sunlance_sun4_remove();
-#else
        of_unregister_driver(&sunlance_sbus_driver);
-#endif
 }
 
 module_init(sparc_lance_init);
index e811331d4608a86abc8514848cdacddf73b83123..f63644744ff9dafafb56eb746d3acf5018b3733f 100644 (file)
@@ -3,7 +3,7 @@
  *          controller out there can be most efficiently programmed
  *          if you make it look like a LANCE.
  *
- * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 1999, 2003, 2006, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
 #include <linux/bitops.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/byteorder.h>
 #include <asm/idprom.h>
-#include <asm/sbus.h>
 #include <asm/openprom.h>
 #include <asm/oplib.h>
 #include <asm/auxio.h>
@@ -40,8 +42,8 @@
 #include "sunqe.h"
 
 #define DRV_NAME       "sunqe"
-#define DRV_VERSION    "4.0"
-#define DRV_RELDATE    "June 23, 2006"
+#define DRV_VERSION    "4.1"
+#define DRV_RELDATE    "August 27, 2008"
 #define DRV_AUTHOR     "David S. Miller (davem@davemloft.net)"
 
 static char version[] =
@@ -690,12 +692,18 @@ static void qe_set_multicast(struct net_device *dev)
 /* Ethtool support... */
 static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+       const struct linux_prom_registers *regs;
        struct sunqe *qep = dev->priv;
+       struct of_device *op;
 
        strcpy(info->driver, "sunqe");
        strcpy(info->version, "3.0");
-       sprintf(info->bus_info, "SBUS:%d",
-               qep->qe_sdev->slot);
+
+       op = qep->op;
+       regs = of_get_property(op->node, "reg", NULL);
+       if (regs)
+               sprintf(info->bus_info, "SBUS:%d", regs->which_io);
+
 }
 
 static u32 qe_get_link(struct net_device *dev)
@@ -717,11 +725,11 @@ static const struct ethtool_ops qe_ethtool_ops = {
 };
 
 /* This is only called once at boot time for each card probed. */
-static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
+static void qec_init_once(struct sunqec *qecp, struct of_device *op)
 {
        u8 bsizes = qecp->qec_bursts;
 
-       if (sbus_can_burst64(qsdev) && (bsizes & DMA_BURST64)) {
+       if (sbus_can_burst64() && (bsizes & DMA_BURST64)) {
                sbus_writel(GLOB_CTRL_B64, qecp->gregs + GLOB_CTRL);
        } else if (bsizes & DMA_BURST32) {
                sbus_writel(GLOB_CTRL_B32, qecp->gregs + GLOB_CTRL);
@@ -735,15 +743,15 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
        sbus_writel(GLOB_PSIZE_2048, qecp->gregs + GLOB_PSIZE);
 
        /* Set the local memsize register, divided up to one piece per QE channel. */
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2),
+       sbus_writel((resource_size(&op->resource[1]) >> 2),
                    qecp->gregs + GLOB_MSIZE);
 
        /* Divide up the local QEC memory amongst the 4 QE receiver and
         * transmitter FIFOs.  Basically it is (total / 2 / num_channels).
         */
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+       sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
                    qecp->gregs + GLOB_TSIZE);
-       sbus_writel((qsdev->reg_addrs[1].reg_size >> 2) >> 1,
+       sbus_writel((resource_size(&op->resource[1]) >> 2) >> 1,
                    qecp->gregs + GLOB_RSIZE);
 }
 
@@ -767,24 +775,21 @@ static u8 __devinit qec_get_burst(struct device_node *dp)
        return bsizes;
 }
 
-static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
+static struct sunqec * __devinit get_qec(struct of_device *child)
 {
-       struct sbus_dev *qec_sdev = child_sdev->parent;
+       struct of_device *op = to_of_device(child->dev.parent);
        struct sunqec *qecp;
 
-       for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
-               if (qecp->qec_sdev == qec_sdev)
-                       break;
-       }
+       qecp = dev_get_drvdata(&op->dev);
        if (!qecp) {
                qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
                if (qecp) {
                        u32 ctrl;
 
-                       qecp->qec_sdev = qec_sdev;
-                       qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
-                                                  GLOB_REG_SIZE,
-                                                  "QEC Global Registers");
+                       qecp->op = op;
+                       qecp->gregs = of_ioremap(&op->resource[0], 0,
+                                                GLOB_REG_SIZE,
+                                                "QEC Global Registers");
                        if (!qecp->gregs)
                                goto fail;
 
@@ -799,16 +804,18 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
                        if (qec_global_reset(qecp->gregs))
                                goto fail;
 
-                       qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
+                       qecp->qec_bursts = qec_get_burst(op->node);
 
-                       qec_init_once(qecp, qec_sdev);
+                       qec_init_once(qecp, op);
 
-                       if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+                       if (request_irq(op->irqs[0], &qec_interrupt,
                                        IRQF_SHARED, "qec", (void *) qecp)) {
                                printk(KERN_ERR "qec: Can't register irq.\n");
                                goto fail;
                        }
 
+                       dev_set_drvdata(&op->dev, qecp);
+
                        qecp->next_module = root_qec_dev;
                        root_qec_dev = qecp;
                }
@@ -818,17 +825,17 @@ static struct sunqec * __devinit get_qec(struct sbus_dev *child_sdev)
 
 fail:
        if (qecp->gregs)
-               sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+               of_iounmap(&op->resource[0], qecp->gregs, GLOB_REG_SIZE);
        kfree(qecp);
        return NULL;
 }
 
-static int __devinit qec_ether_init(struct sbus_dev *sdev)
+static int __devinit qec_ether_init(struct of_device *op)
 {
        static unsigned version_printed;
        struct net_device *dev;
-       struct sunqe *qe;
        struct sunqec *qecp;
+       struct sunqe *qe;
        int i, res;
 
        if (version_printed++ == 0)
@@ -842,49 +849,42 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
 
        qe = netdev_priv(dev);
 
-       i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
-       if (i == -1) {
-               struct sbus_dev *td = sdev->parent->child;
-               i = 0;
-               while (td != sdev) {
-                       td = td->next;
-                       i++;
-               }
-       }
+       res = -ENODEV;
+
+       i = of_getintprop_default(op->node, "channel#", -1);
+       if (i == -1)
+               goto fail;
        qe->channel = i;
        spin_lock_init(&qe->lock);
 
-       res = -ENODEV;
-       qecp = get_qec(sdev);
+       qecp = get_qec(op);
        if (!qecp)
                goto fail;
 
        qecp->qes[qe->channel] = qe;
        qe->dev = dev;
        qe->parent = qecp;
-       qe->qe_sdev = sdev;
+       qe->op = op;
 
        res = -ENOMEM;
-       qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
-                                 CREG_REG_SIZE, "QEC Channel Registers");
+       qe->qcregs = of_ioremap(&op->resource[0], 0,
+                               CREG_REG_SIZE, "QEC Channel Registers");
        if (!qe->qcregs) {
                printk(KERN_ERR "qe: Cannot map channel registers.\n");
                goto fail;
        }
 
-       qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
-                                MREGS_REG_SIZE, "QE MACE Registers");
+       qe->mregs = of_ioremap(&op->resource[1], 0,
+                              MREGS_REG_SIZE, "QE MACE Registers");
        if (!qe->mregs) {
                printk(KERN_ERR "qe: Cannot map MACE registers.\n");
                goto fail;
        }
 
-       qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
-                                            PAGE_SIZE,
-                                            &qe->qblock_dvma);
-       qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
-                                           sizeof(struct sunqe_buffers),
-                                           &qe->buffers_dvma);
+       qe->qe_block = dma_alloc_coherent(&op->dev, PAGE_SIZE,
+                                         &qe->qblock_dvma, GFP_ATOMIC);
+       qe->buffers = dma_alloc_coherent(&op->dev, sizeof(struct sunqe_buffers),
+                                        &qe->buffers_dvma, GFP_ATOMIC);
        if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
            qe->buffers == NULL || qe->buffers_dvma == 0)
                goto fail;
@@ -892,7 +892,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        /* Stop this QE. */
        qe_stop(qe);
 
-       SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+       SET_NETDEV_DEV(dev, &op->dev);
 
        dev->open = qe_open;
        dev->stop = qe_close;
@@ -900,7 +900,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        dev->set_multicast_list = qe_set_multicast;
        dev->tx_timeout = qe_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
-       dev->irq = sdev->irqs[0];
+       dev->irq = op->irqs[0];
        dev->dma = 0;
        dev->ethtool_ops = &qe_ethtool_ops;
 
@@ -908,7 +908,7 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
        if (res)
                goto fail;
 
-       dev_set_drvdata(&sdev->ofdev.dev, qe);
+       dev_set_drvdata(&op->dev, qe);
 
        printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
        for (i = 0; i < 6; i++)
@@ -922,58 +922,50 @@ static int __devinit qec_ether_init(struct sbus_dev *sdev)
 
 fail:
        if (qe->qcregs)
-               sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+               of_iounmap(&op->resource[0], qe->qcregs, CREG_REG_SIZE);
        if (qe->mregs)
-               sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+               of_iounmap(&op->resource[1], qe->mregs, MREGS_REG_SIZE);
        if (qe->qe_block)
-               sbus_free_consistent(qe->qe_sdev,
-                                    PAGE_SIZE,
-                                    qe->qe_block,
-                                    qe->qblock_dvma);
+               dma_free_coherent(&op->dev, PAGE_SIZE,
+                                 qe->qe_block, qe->qblock_dvma);
        if (qe->buffers)
-               sbus_free_consistent(qe->qe_sdev,
-                                    sizeof(struct sunqe_buffers),
-                                    qe->buffers,
-                                    qe->buffers_dvma);
+               dma_free_coherent(&op->dev,
+                                 sizeof(struct sunqe_buffers),
+                                 qe->buffers,
+                                 qe->buffers_dvma);
 
        free_netdev(dev);
 
        return res;
 }
 
-static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qec_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return qec_ether_init(sdev);
+       return qec_ether_init(op);
 }
 
-static int __devexit qec_sbus_remove(struct of_device *dev)
+static int __devexit qec_sbus_remove(struct of_device *op)
 {
-       struct sunqe *qp = dev_get_drvdata(&dev->dev);
+       struct sunqe *qp = dev_get_drvdata(&op->dev);
        struct net_device *net_dev = qp->dev;
 
        unregister_netdev(net_dev);
 
-       sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
-       sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
-       sbus_free_consistent(qp->qe_sdev,
-                            PAGE_SIZE,
-                            qp->qe_block,
-                            qp->qblock_dvma);
-       sbus_free_consistent(qp->qe_sdev,
-                            sizeof(struct sunqe_buffers),
-                            qp->buffers,
-                            qp->buffers_dvma);
+       of_iounmap(&op->resource[0], qp->qcregs, CREG_REG_SIZE);
+       of_iounmap(&op->resource[1], qp->mregs, MREGS_REG_SIZE);
+       dma_free_coherent(&op->dev, PAGE_SIZE,
+                         qp->qe_block, qp->qblock_dvma);
+       dma_free_coherent(&op->dev, sizeof(struct sunqe_buffers),
+                         qp->buffers, qp->buffers_dvma);
 
        free_netdev(net_dev);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id qec_sbus_match[] = {
+static const struct of_device_id qec_sbus_match[] = {
        {
                .name = "qe",
        },
@@ -991,7 +983,7 @@ static struct of_platform_driver qec_sbus_driver = {
 
 static int __init qec_init(void)
 {
-       return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&qec_sbus_driver, &of_bus_type);
 }
 
 static void __exit qec_exit(void)
@@ -1000,11 +992,11 @@ static void __exit qec_exit(void)
 
        while (root_qec_dev) {
                struct sunqec *next = root_qec_dev->next_module;
+               struct of_device *op = root_qec_dev->op;
 
-               free_irq(root_qec_dev->qec_sdev->irqs[0],
-                        (void *) root_qec_dev);
-               sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
-
+               free_irq(op->irqs[0], (void *) root_qec_dev);
+               of_iounmap(&op->resource[0], root_qec_dev->gregs,
+                          GLOB_REG_SIZE);
                kfree(root_qec_dev);
 
                root_qec_dev = next;
index 347c8ddc1592a447109c8a4f94bf3e8d45d2e432..5813a7b2faa5692eb935c7387393771daa3b672b 100644 (file)
@@ -314,7 +314,7 @@ struct sunqec {
        void __iomem            *gregs;         /* QEC Global Registers         */
        struct sunqe            *qes[4];        /* Each child MACE              */
        unsigned int            qec_bursts;     /* Support burst sizes          */
-       struct sbus_dev         *qec_sdev;      /* QEC's SBUS device            */
+       struct of_device        *op;            /* QEC's OF device              */
        struct sunqec           *next_module;   /* List of all QECs in system   */
 };
 
@@ -342,7 +342,7 @@ struct sunqe {
        __u32                           buffers_dvma;   /* DVMA visible address.       */
        struct sunqec                   *parent;
        u8                              mconfig;        /* Base MACE mconfig value     */
-       struct sbus_dev                 *qe_sdev;       /* QE's SBUS device struct     */
+       struct of_device                *op;            /* QE's OF device struct       */
        struct net_device               *dev;           /* QE's netdevice struct       */
        int                             channel;        /* Who am I?                   */
 };
index 6415ce15c2efef51721b0a50b181ee296f98ad28..a720065553df48645f121c86b11bcf8bf5c61e52 100644 (file)
@@ -1,6 +1,6 @@
 /* sunvnet.c: Sun LDOM Virtual Network Driver.
  *
- * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
 #include <linux/module.h>
@@ -1260,7 +1260,7 @@ static int vnet_port_remove(struct vio_dev *vdev)
        return 0;
 }
 
-static struct vio_device_id vnet_port_match[] = {
+static const struct vio_device_id vnet_port_match[] = {
        {
                .type = "vnet-port",
        },
index c749bdba214ce1fb686daaa2c80eda4237f49fcc..3c3dd403f5ddd9f58bed9f632baad6b72409e0ee 100644 (file)
@@ -1794,10 +1794,10 @@ static struct xenbus_driver netfront = {
 
 static int __init netif_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return 0;
 
        printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
@@ -1809,7 +1809,7 @@ module_init(netif_init);
 
 static void __exit netif_exit(void)
 {
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return;
 
        xenbus_unregister_driver(&netfront);
index 9d595aa91e4605e9a9193661119c131ee7494b4b..065f229580d5cfc3acd8d740597bb638c558a889 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/parport.h>
 
@@ -34,7 +36,6 @@
 
 #include <asm/io.h>
 #include <asm/oplib.h>           /* OpenProm Library */
-#include <asm/sbus.h>
 #include <asm/dma.h>             /* BPP uses LSI 64854 for DMA */
 #include <asm/irq.h>
 #include <asm/sunbpp.h>
@@ -285,38 +286,37 @@ static struct parport_operations parport_sunbpp_ops =
        .owner          = THIS_MODULE,
 };
 
-static int __devinit init_one_port(struct sbus_dev *sdev)
+static int __devinit bpp_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct parport *p;
-       /* at least in theory there may be a "we don't dma" case */
        struct parport_operations *ops;
-       void __iomem *base;
-       int irq, dma, err = 0, size;
        struct bpp_regs __iomem *regs;
+       int irq, dma, err = 0, size;
        unsigned char value_tcr;
+       void __iomem *base;
+       struct parport *p;
 
-       irq = sdev->irqs[0];
-       base = sbus_ioremap(&sdev->resource[0], 0,
-                           sdev->reg_addrs[0].reg_size, 
-                           "sunbpp");
+       irq = op->irqs[0];
+       base = of_ioremap(&op->resource[0], 0,
+                         resource_size(&op->resource[0]),
+                         "sunbpp");
        if (!base)
                return -ENODEV;
 
-       size = sdev->reg_addrs[0].reg_size;
+       size = resource_size(&op->resource[0]);
        dma = PARPORT_DMA_NONE;
 
        ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
         if (!ops)
                goto out_unmap;
 
-        memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
+        memcpy (ops, &parport_sunbpp_ops, sizeof(struct parport_operations));
 
        dprintk(("register_port\n"));
        if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
                goto out_free_ops;
 
        p->size = size;
-       p->dev = &sdev->ofdev.dev;
+       p->dev = &op->dev;
 
        if ((err = request_irq(p->irq, parport_irq_handler,
                               IRQF_SHARED, p->name, p)) != 0) {
@@ -333,7 +333,7 @@ static int __devinit init_one_port(struct sbus_dev *sdev)
 
        printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
 
-       dev_set_drvdata(&sdev->ofdev.dev, p);
+       dev_set_drvdata(&op->dev, p);
 
        parport_announce_port(p);
 
@@ -346,21 +346,14 @@ out_free_ops:
        kfree(ops);
 
 out_unmap:
-       sbus_iounmap(base, size);
+       of_iounmap(&op->resource[0], base, size);
 
        return err;
 }
 
-static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return init_one_port(sdev);
-}
-
-static int __devexit bpp_remove(struct of_device *dev)
+static int __devexit bpp_remove(struct of_device *op)
 {
-       struct parport *p = dev_get_drvdata(&dev->dev);
+       struct parport *p = dev_get_drvdata(&op->dev);
        struct parport_operations *ops = p->ops;
 
        parport_remove_port(p);
@@ -370,16 +363,16 @@ static int __devexit bpp_remove(struct of_device *dev)
                free_irq(p->irq, p);
        }
 
-       sbus_iounmap((void __iomem *) p->base, p->size);
+       of_iounmap(&op->resource[0], (void __iomem *) p->base, p->size);
        parport_put_port(p);
        kfree(ops);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id bpp_match[] = {
+static const struct of_device_id bpp_match[] = {
        {
                .name = "SUNW,bpp",
        },
@@ -397,7 +390,7 @@ static struct of_platform_driver bpp_sbus_driver = {
 
 static int __init parport_sunbpp_init(void)
 {
-       return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&bpp_sbus_driver, &of_bus_type);
 }
 
 static void __exit parport_sunbpp_exit(void)
index 1982f8b4278218997e3a73fb3724c2c86d36c3b6..63bb579104452f0c8228e7fbbf5bccedcb37f8f6 100644 (file)
@@ -58,7 +58,7 @@ config BATTERY_TOSA
 
 config BATTERY_WM97XX
        bool "WM97xx generic battery driver"
-       depends on TOUCHSCREEN_WM97XX
+       depends on TOUCHSCREEN_WM97XX=y
        help
          Say Y to enable support for battery measured by WM97xx aux port.
 
index 9a9755c92fada3268f03f69ee7270964bf322818..b57fba5c6d027d645573ae070649d745bab26950 100644 (file)
@@ -329,7 +329,7 @@ comment "Platform RTC drivers"
 
 config RTC_DRV_CMOS
        tristate "PC-style 'CMOS'"
-       depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
+       depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
        default y if X86
        help
          Say "yes" here to get direct support for the real time clock
@@ -406,14 +406,26 @@ config RTC_DRV_M48T86
          will be called rtc-m48t86.
 
 config RTC_DRV_M48T59
-       tristate "ST M48T59"
+       tristate "ST M48T59/M48T08/M48T02"
        help
          If you say Y here you will get support for the
-         ST M48T59 RTC chip.
+         ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
+
+         These chips are usually found in Sun SPARC and UltraSPARC
+         workstations.
 
          This driver can also be built as a module, if so, the module
          will be called "rtc-m48t59".
 
+config RTC_DRV_BQ4802
+       tristate "TI BQ4802"
+       help
+         If you say Y here you will get support for the TI
+         BQ4802 RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-bq4802.
+
 config RTC_DRV_V3020
        tristate "EM Microelectronic V3020"
        help
@@ -583,4 +595,18 @@ config RTC_DRV_PPC
         the RTC. This exposes that functionality through the generic RTC
         class.
 
+config RTC_DRV_SUN4V
+       bool "SUN4V Hypervisor RTC"
+       depends on SPARC64
+       help
+         If you say Y here you will get support for the Hypervisor
+         based RTC on SUN4V systems.
+
+config RTC_DRV_STARFIRE
+       bool "Starfire RTC"
+       depends on SPARC64
+       help
+         If you say Y here you will get support for the RTC found on
+         Starfire systems.
+
 endif # RTC_CLASS
index 18622ef84cab0c4f48e15aa437edccff357136e4..10f41f85c38a0fbbea375e7d38b5ef1ea3a805a1 100644 (file)
@@ -38,6 +38,9 @@ obj-$(CONFIG_RTC_DRV_M41T80)  += rtc-m41t80.o
 obj-$(CONFIG_RTC_DRV_M41T94)   += rtc-m41t94.o
 obj-$(CONFIG_RTC_DRV_M48T59)   += rtc-m48t59.o
 obj-$(CONFIG_RTC_DRV_M48T86)   += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_BQ4802)   += rtc-bq4802.o
+obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_MAX6900)  += rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)  += rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_OMAP)     += rtc-omap.o
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
new file mode 100644 (file)
index 0000000..189a018
--- /dev/null
@@ -0,0 +1,230 @@
+/* rtc-bq4802.c: TI BQ4802 RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("TI BQ4802 RTC driver");
+MODULE_LICENSE("GPL");
+
+struct bq4802 {
+       void __iomem            *regs;
+       unsigned long           ioport;
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+       struct resource         *r;
+       u8 (*read)(struct bq4802 *, int);
+       void (*write)(struct bq4802 *, int, u8);
+};
+
+static u8 bq4802_read_io(struct bq4802 *p, int off)
+{
+       return inb(p->ioport + off);
+}
+
+static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
+{
+       outb(val, p->ioport + off);
+}
+
+static u8 bq4802_read_mem(struct bq4802 *p, int off)
+{
+       return readb(p->regs + off);
+}
+
+static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
+{
+       writeb(val, p->regs + off);
+}
+
+static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bq4802 *p = platform_get_drvdata(pdev);
+       unsigned long flags;
+       unsigned int century;
+       u8 val;
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       val = p->read(p, 0x0e);
+       p->write(p, 0xe, val | 0x08);
+
+       tm->tm_sec = p->read(p, 0x00);
+       tm->tm_min = p->read(p, 0x02);
+       tm->tm_hour = p->read(p, 0x04);
+       tm->tm_mday = p->read(p, 0x06);
+       tm->tm_mon = p->read(p, 0x09);
+       tm->tm_year = p->read(p, 0x0a);
+       tm->tm_wday = p->read(p, 0x08);
+       century = p->read(p, 0x0f);
+
+       p->write(p, 0x0e, val);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       BCD_TO_BIN(tm->tm_sec);
+       BCD_TO_BIN(tm->tm_min);
+       BCD_TO_BIN(tm->tm_hour);
+       BCD_TO_BIN(tm->tm_mday);
+       BCD_TO_BIN(tm->tm_mon);
+       BCD_TO_BIN(tm->tm_year);
+       BCD_TO_BIN(tm->tm_wday);
+       BCD_TO_BIN(century);
+
+       tm->tm_year += (century * 100);
+       tm->tm_year -= 1900;
+
+       tm->tm_mon--;
+
+       return 0;
+}
+
+static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct bq4802 *p = platform_get_drvdata(pdev);
+       u8 sec, min, hrs, day, mon, yrs, century, val;
+       unsigned long flags;
+       unsigned int year;
+
+       year = tm->tm_year + 1900;
+       century = year / 100;
+       yrs = year % 100;
+
+       mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
+       day = tm->tm_mday;
+       hrs = tm->tm_hour;
+       min = tm->tm_min;
+       sec = tm->tm_sec;
+
+       BIN_TO_BCD(sec);
+       BIN_TO_BCD(min);
+       BIN_TO_BCD(hrs);
+       BIN_TO_BCD(day);
+       BIN_TO_BCD(mon);
+       BIN_TO_BCD(yrs);
+       BIN_TO_BCD(century);
+
+       spin_lock_irqsave(&p->lock, flags);
+
+       val = p->read(p, 0x0e);
+       p->write(p, 0x0e, val | 0x08);
+
+       p->write(p, 0x00, sec);
+       p->write(p, 0x02, min);
+       p->write(p, 0x04, hrs);
+       p->write(p, 0x06, day);
+       p->write(p, 0x09, mon);
+       p->write(p, 0x0a, yrs);
+       p->write(p, 0x0f, century);
+
+       p->write(p, 0x0e, val);
+
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return 0;
+}
+
+static const struct rtc_class_ops bq4802_ops = {
+       .read_time      = bq4802_read_time,
+       .set_time       = bq4802_set_time,
+};
+
+static int __devinit bq4802_probe(struct platform_device *pdev)
+{
+       struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+       int err = -ENOMEM;
+
+       if (!p)
+               goto out;
+
+       spin_lock_init(&p->lock);
+
+       p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!p->r) {
+               p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
+               err = -EINVAL;
+               if (!p->r)
+                       goto out_free;
+       }
+       if (p->r->flags & IORESOURCE_IO) {
+               p->ioport = p->r->start;
+               p->read = bq4802_read_io;
+               p->write = bq4802_write_io;
+       } else if (p->r->flags & IORESOURCE_MEM) {
+               p->regs = ioremap(p->r->start, resource_size(p->r));
+               p->read = bq4802_read_mem;
+               p->write = bq4802_write_mem;
+       } else {
+               err = -EINVAL;
+               goto out_free;
+       }
+
+       p->rtc = rtc_device_register("bq4802", &pdev->dev,
+                                    &bq4802_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               err = PTR_ERR(p->rtc);
+               goto out_iounmap;
+       }
+
+       platform_set_drvdata(pdev, p);
+       err = 0;
+out:
+       return err;
+
+out_iounmap:
+       if (p->r->flags & IORESOURCE_MEM)
+               iounmap(p->regs);
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit bq4802_remove(struct platform_device *pdev)
+{
+       struct bq4802 *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       if (p->r->flags & IORESOURCE_MEM)
+               iounmap(p->regs);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(p);
+
+       return 0;
+}
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:rtc-bq4802");
+
+static struct platform_driver bq4802_driver = {
+       .driver         = {
+               .name   = "rtc-bq4802",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = bq4802_probe,
+       .remove         = __devexit_p(bq4802_remove),
+};
+
+static int __init bq4802_init(void)
+{
+       return platform_driver_register(&bq4802_driver);
+}
+
+static void __exit bq4802_exit(void)
+{
+       platform_driver_unregister(&bq4802_driver);
+}
+
+module_init(bq4802_init);
+module_exit(bq4802_exit);
index b184367637d06d65f09b2b8af2517e077ad37de2..b23af0c2a869181e5b4fb5480546b93103d93d40 100644 (file)
@@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
         */
 #if    defined(CONFIG_ATARI)
        address_space = 64;
-#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
+#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
        address_space = 128;
 #else
 #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@@ -699,7 +699,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        /* FIXME teach the alarm code how to handle binary mode;
         * <asm-generic/rtc.h> doesn't know 12-hour mode either.
         */
-       if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+       if (is_valid_irq(rtc_irq) &&
+           (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
                dev_dbg(dev, "only 24-hr BCD mode supported\n");
                retval = -ENXIO;
                goto cleanup1;
index 013e6c103b9c465f1cc66eabe1d3011e697b5704..ce4eff6a8d51bd57057c4d0e8f24f49304c4ab60 100644 (file)
@@ -24,8 +24,9 @@
 #define NO_IRQ (-1)
 #endif
 
-#define M48T59_READ(reg)       pdata->read_byte(dev, reg)
-#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
+#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
+#define M48T59_WRITE(val, reg) \
+       (pdata->write_byte(dev, pdata->offset + reg, val))
 
 #define M48T59_SET_BITS(mask, reg)     \
        M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@@ -34,7 +35,6 @@
 
 struct m48t59_private {
        void __iomem *ioaddr;
-       unsigned int size; /* iomem size */
        int irq;
        struct rtc_device *rtc;
        spinlock_t lock; /* serialize the NVRAM and RTC access */
@@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
        tm->tm_mday     = BCD2BIN(M48T59_READ(M48T59_MDAY));
 
        val = M48T59_READ(M48T59_WDAY);
-       if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+       if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
+           (val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
                dev_dbg(dev, "Century bit is enabled\n");
                tm->tm_year += 100;     /* one century */
        }
@@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
        M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
        M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
 
-       if (tm->tm_year/100)
+       if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
                val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
        val |= (BIN2BCD(tm->tm_wday) & 0x07);
        M48T59_WRITE(val, M48T59_WDAY);
@@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = {
        .proc           = m48t59_rtc_proc,
 };
 
+static const struct rtc_class_ops m48t02_rtc_ops = {
+       .read_time      = m48t59_rtc_read_time,
+       .set_time       = m48t59_rtc_set_time,
+};
+
 static ssize_t m48t59_nvram_read(struct kobject *kobj,
                                struct bin_attribute *bin_attr,
                                char *buf, loff_t pos, size_t size)
@@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
        ssize_t cnt = 0;
        unsigned long flags;
 
-       for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+       for (; size > 0 && pos < pdata->offset; cnt++, size--) {
                spin_lock_irqsave(&m48t59->lock, flags);
                *buf++ = M48T59_READ(cnt);
                spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj,
        ssize_t cnt = 0;
        unsigned long flags;
 
-       for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+       for (; size > 0 && pos < pdata->offset; cnt++, size--) {
                spin_lock_irqsave(&m48t59->lock, flags);
                M48T59_WRITE(*buf++, cnt);
                spin_unlock_irqrestore(&m48t59->lock, flags);
@@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = {
        },
        .read = m48t59_nvram_read,
        .write = m48t59_nvram_write,
-       .size = M48T59_NVRAM_SIZE,
 };
 
 static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
        struct m48t59_private *m48t59 = NULL;
        struct resource *res;
        int ret = -ENOMEM;
+       char *name;
+       const struct rtc_class_ops *ops;
 
        /* This chip could be memory-mapped or I/O-mapped */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
                        /* Ensure we only kmalloc platform data once */
                        pdev->dev.platform_data = pdata;
                }
+               if (!pdata->type)
+                       pdata->type = M48T59RTC_TYPE_M48T59;
 
                /* Try to use the generic memory read/write ops */
                if (!pdata->write_byte)
@@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
        if (!m48t59)
                return -ENOMEM;
 
-       m48t59->size = res->end - res->start + 1;
-       m48t59->ioaddr = ioremap(res->start, m48t59->size);
-       if (!m48t59->ioaddr)
-               goto out;
+       m48t59->ioaddr = pdata->ioaddr;
+
+       if (!m48t59->ioaddr) {
+               /* ioaddr not mapped externally */
+               m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
+               if (!m48t59->ioaddr)
+                       goto out;
+       }
 
        /* Try to get irq number. We also can work in
         * the mode without IRQ.
@@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
                if (ret)
                        goto out;
        }
+       switch (pdata->type) {
+       case M48T59RTC_TYPE_M48T59:
+               name = "m48t59";
+               ops = &m48t59_rtc_ops;
+               pdata->offset = 0x1ff0;
+               break;
+       case M48T59RTC_TYPE_M48T02:
+               name = "m48t02";
+               ops = &m48t02_rtc_ops;
+               pdata->offset = 0x7f0;
+               break;
+       case M48T59RTC_TYPE_M48T08:
+               name = "m48t08";
+               ops = &m48t02_rtc_ops;
+               pdata->offset = 0x1ff0;
+               break;
+       default:
+               dev_err(&pdev->dev, "Unknown RTC type\n");
+               ret = -ENODEV;
+               goto out;
+       }
 
-       m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
-                               &m48t59_rtc_ops, THIS_MODULE);
+       m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
        if (IS_ERR(m48t59->rtc)) {
                ret = PTR_ERR(m48t59->rtc);
                goto out;
        }
 
+       m48t59_nvram_attr.size = pdata->offset;
+
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
        if (ret)
                goto out;
@@ -452,11 +487,12 @@ out:
 static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
 {
        struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+       struct m48t59_plat_data *pdata = pdev->dev.platform_data;
 
        sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
        if (!IS_ERR(m48t59->rtc))
                rtc_device_unregister(m48t59->rtc);
-       if (m48t59->ioaddr)
+       if (m48t59->ioaddr && !pdata->ioaddr)
                iounmap(m48t59->ioaddr);
        if (m48t59->irq != NO_IRQ)
                free_irq(m48t59->irq, &pdev->dev);
@@ -491,5 +527,5 @@ module_init(m48t59_rtc_init);
 module_exit(m48t59_rtc_exit);
 
 MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
-MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c
new file mode 100644 (file)
index 0000000..7ccb0dd
--- /dev/null
@@ -0,0 +1,120 @@
+/* rtc-starfire.c: Starfire platform RTC driver.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/oplib.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("Starfire RTC driver");
+MODULE_LICENSE("GPL");
+
+struct starfire_rtc {
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+};
+
+static u32 starfire_get_time(void)
+{
+       static char obp_gettod[32];
+       static u32 unix_tod;
+
+       sprintf(obp_gettod, "h# %08x unix-gettod",
+               (unsigned int) (long) &unix_tod);
+       prom_feval(obp_gettod);
+
+       return unix_tod;
+}
+
+static int starfire_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct starfire_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+
+       spin_lock_irqsave(&p->lock, flags);
+       secs = starfire_get_time();
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       rtc_time_to_tm(secs, tm);
+
+       return 0;
+}
+
+static int starfire_set_time(struct device *dev, struct rtc_time *tm)
+{
+       unsigned long secs;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err)
+               return err;
+
+       /* Do nothing, time is set using the service processor
+        * console on this platform.
+        */
+       return 0;
+}
+
+static const struct rtc_class_ops starfire_rtc_ops = {
+       .read_time      = starfire_read_time,
+       .set_time       = starfire_set_time,
+};
+
+static int __devinit starfire_rtc_probe(struct platform_device *pdev)
+{
+       struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+       if (!p)
+               return -ENOMEM;
+
+       spin_lock_init(&p->lock);
+
+       p->rtc = rtc_device_register("starfire", &pdev->dev,
+                                    &starfire_rtc_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               int err = PTR_ERR(p->rtc);
+               kfree(p);
+               return err;
+       }
+       platform_set_drvdata(pdev, p);
+       return 0;
+}
+
+static int __devexit starfire_rtc_remove(struct platform_device *pdev)
+{
+       struct starfire_rtc *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       kfree(p);
+
+       return 0;
+}
+
+static struct platform_driver starfire_rtc_driver = {
+       .driver         = {
+               .name   = "rtc-starfire",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = starfire_rtc_probe,
+       .remove         = __devexit_p(starfire_rtc_remove),
+};
+
+static int __init starfire_rtc_init(void)
+{
+       return platform_driver_register(&starfire_rtc_driver);
+}
+
+static void __exit starfire_rtc_exit(void)
+{
+       platform_driver_unregister(&starfire_rtc_driver);
+}
+
+module_init(starfire_rtc_init);
+module_exit(starfire_rtc_exit);
diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c
new file mode 100644 (file)
index 0000000..2012ccb
--- /dev/null
@@ -0,0 +1,153 @@
+/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+#include <asm/hypervisor.h>
+
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_DESCRIPTION("SUN4V RTC driver");
+MODULE_LICENSE("GPL");
+
+struct sun4v_rtc {
+       struct rtc_device       *rtc;
+       spinlock_t              lock;
+};
+
+static unsigned long hypervisor_get_time(void)
+{
+       unsigned long ret, time;
+       int retries = 10000;
+
+retry:
+       ret = sun4v_tod_get(&time);
+       if (ret == HV_EOK)
+               return time;
+       if (ret == HV_EWOULDBLOCK) {
+               if (--retries > 0) {
+                       udelay(100);
+                       goto retry;
+               }
+               printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
+               return 0;
+       }
+       printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
+       return 0;
+}
+
+static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sun4v_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+
+       spin_lock_irqsave(&p->lock, flags);
+       secs = hypervisor_get_time();
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       rtc_time_to_tm(secs, tm);
+
+       return 0;
+}
+
+static int hypervisor_set_time(unsigned long secs)
+{
+       unsigned long ret;
+       int retries = 10000;
+
+retry:
+       ret = sun4v_tod_set(secs);
+       if (ret == HV_EOK)
+               return 0;
+       if (ret == HV_EWOULDBLOCK) {
+               if (--retries > 0) {
+                       udelay(100);
+                       goto retry;
+               }
+               printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
+               return -EAGAIN;
+       }
+       printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
+       return -EOPNOTSUPP;
+}
+
+static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sun4v_rtc *p = dev_get_drvdata(dev);
+       unsigned long flags, secs;
+       int err;
+
+       err = rtc_tm_to_time(tm, &secs);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&p->lock, flags);
+       err = hypervisor_set_time(secs);
+       spin_unlock_irqrestore(&p->lock, flags);
+
+       return err;
+}
+
+static const struct rtc_class_ops sun4v_rtc_ops = {
+       .read_time      = sun4v_read_time,
+       .set_time       = sun4v_set_time,
+};
+
+static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
+{
+       struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+
+       if (!p)
+               return -ENOMEM;
+
+       spin_lock_init(&p->lock);
+
+       p->rtc = rtc_device_register("sun4v", &pdev->dev,
+                                    &sun4v_rtc_ops, THIS_MODULE);
+       if (IS_ERR(p->rtc)) {
+               int err = PTR_ERR(p->rtc);
+               kfree(p);
+               return err;
+       }
+       platform_set_drvdata(pdev, p);
+       return 0;
+}
+
+static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
+{
+       struct sun4v_rtc *p = platform_get_drvdata(pdev);
+
+       rtc_device_unregister(p->rtc);
+       kfree(p);
+
+       return 0;
+}
+
+static struct platform_driver sun4v_rtc_driver = {
+       .driver         = {
+               .name   = "rtc-sun4v",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = sun4v_rtc_probe,
+       .remove         = __devexit_p(sun4v_rtc_remove),
+};
+
+static int __init sun4v_rtc_init(void)
+{
+       return platform_driver_register(&sun4v_rtc_driver);
+}
+
+static void __exit sun4v_rtc_exit(void)
+{
+       platform_driver_unregister(&sun4v_rtc_driver);
+}
+
+module_init(sun4v_rtc_init);
+module_exit(sun4v_rtc_exit);
index 7b1d24d95308dcc32e79b2e7e95163111bf7287a..e94dc25805f9c3cb6076d1dd887e64dc8f62b619 100644 (file)
@@ -2,8 +2,4 @@
 # Makefile for the linux kernel.
 #
 
-ifneq ($(ARCH),m68k)
-obj-y    := sbus.o dvma.o
-endif
-
 obj-$(CONFIG_SBUSCHAR) += char/
index 400c65bfb8c75f338664b9ebb11fb337ed0c23ea..73cde85d04d88cf4c10aa924e4e73980f81c9bb7 100644 (file)
@@ -13,16 +13,6 @@ config SUN_OPENPROMIO
 
          If unsure, say Y.
 
-config SUN_MOSTEK_RTC
-       tristate "Mostek real time clock support"
-       depends on SPARC32
-       help
-         The Mostek RTC chip is used on all known Sun computers except
-         some JavaStations. For a JavaStation you need to say Y both here
-         and to "Enhanced Real Time Clock Support".
-
-         Say Y here unless you are building a special purpose kernel.
-
 config OBP_FLASH
        tristate "OBP Flash Device support"
        depends on SPARC64
@@ -30,26 +20,9 @@ config OBP_FLASH
          The OpenBoot PROM on Ultra systems is flashable. If you want to be
          able to upgrade the OBP firmware, say Y here.
 
-config SUN_BPP
-       tristate "Bidirectional parallel port support (OBSOLETE)"
-       depends on EXPERIMENTAL
-       help
-         Say Y here to support Sun's obsolete variant of IEEE1284
-         bidirectional parallel port protocol as /dev/bppX.  Can be built on
-         x86 machines.
-
-config SUN_VIDEOPIX
-       tristate "Videopix Frame Grabber (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && (BROKEN || !64BIT)
-       help
-         Say Y here to support the Videopix Frame Grabber from Sun
-         Microsystems, commonly found on SPARCstations.  This card, which is
-         based on the Phillips SAA9051, can handle NTSC and PAL/SECAM and
-         SVIDEO signals.
-
 config TADPOLE_TS102_UCTRL
        tristate "Tadpole TS102 Microcontroller support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && SPARC32
+       depends on EXPERIMENTAL
        help
          Say Y here to directly support the TS102 Microcontroller interface
          on the Tadpole Sparcbook 3.  This device handles power-management
index 7ab060e9a5fe25cd50b8bbfe75c0355a14fb065c..78b6183c9866865dc57d3da287889557422fb427 100644 (file)
@@ -7,18 +7,12 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-vfc-objs := vfc_dev.o vfc_i2c.o
 bbc-objs := bbc_i2c.o bbc_envctrl.o
 
 obj-$(CONFIG_ENVCTRL)                  += envctrl.o
 obj-$(CONFIG_DISPLAY7SEG)              += display7seg.o
-obj-$(CONFIG_WATCHDOG_CP1XXX)          += cpwatchdog.o
-obj-$(CONFIG_WATCHDOG_RIO)             += riowatchdog.o
 obj-$(CONFIG_OBP_FLASH)                        += flash.o
 obj-$(CONFIG_SUN_OPENPROMIO)           += openprom.o
-obj-$(CONFIG_SUN_MOSTEK_RTC)           += rtc.o
-obj-$(CONFIG_SUN_BPP)                  += bpp.o
-obj-$(CONFIG_SUN_VIDEOPIX)             += vfc.o
 obj-$(CONFIG_TADPOLE_TS102_UCTRL)      += uctrl.o
 obj-$(CONFIG_SUN_JSFLASH)              += jsflash.o
 obj-$(CONFIG_BBC_I2C)                  += bbc.o
index 0bde26989a23a2ebaf89251414fe58cf384ea84a..15dab96d05e31328108b89dabc53ee4b2b5aa573 100644 (file)
@@ -1,15 +1,15 @@
-/* $Id: bbc_envctrl.c,v 1.4 2001/04/06 16:48:08 davem Exp $
- * bbc_envctrl.c: UltraSPARC-III environment control driver.
+/* bbc_envctrl.c: UltraSPARC-III environment control driver.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
 #include <linux/reboot.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/oplib.h>
-#include <asm/ebus.h>
 
 #include "bbc_i2c.h"
 #include "max1617.h"
@@ -75,43 +75,8 @@ static struct temp_limits amb_temp_limits[2] = {
        { 65, 55, 40, 5, -5, -10 },
 };
 
-enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
-
-struct bbc_cpu_temperature {
-       struct bbc_cpu_temperature      *next;
-
-       struct bbc_i2c_client           *client;
-       int                             index;
-
-       /* Current readings, and history. */
-       s8                              curr_cpu_temp;
-       s8                              curr_amb_temp;
-       s8                              prev_cpu_temp;
-       s8                              prev_amb_temp;
-       s8                              avg_cpu_temp;
-       s8                              avg_amb_temp;
-
-       int                             sample_tick;
-
-       enum fan_action                 fan_todo[2];
-#define FAN_AMBIENT    0
-#define FAN_CPU                1
-};
-
-struct bbc_cpu_temperature *all_bbc_temps;
-
-struct bbc_fan_control {
-       struct bbc_fan_control  *next;
-
-       struct bbc_i2c_client   *client;
-       int                     index;
-
-       int                     psupply_fan_on;
-       int                     cpu_fan_speed;
-       int                     system_fan_speed;
-};
-
-struct bbc_fan_control *all_bbc_fans;
+static LIST_HEAD(all_temps);
+static LIST_HEAD(all_fans);
 
 #define CPU_FAN_REG    0xf0
 #define SYS_FAN_REG    0xf2
@@ -330,7 +295,7 @@ static enum fan_action prioritize_fan_action(int which_fan)
         * recommend we do, and perform that action on all the
         * fans.
         */
-       for (tp = all_bbc_temps; tp; tp = tp->next) {
+       list_for_each_entry(tp, &all_temps, glob_list) {
                if (tp->fan_todo[which_fan] == FAN_FULLBLAST) {
                        decision = FAN_FULLBLAST;
                        break;
@@ -439,7 +404,7 @@ static void fans_full_blast(void)
        /* Since we will not be monitoring things anymore, put
         * the fans on full blast.
         */
-       for (fp = all_bbc_fans; fp; fp = fp->next) {
+       list_for_each_entry(fp, &all_fans, glob_list) {
                fp->cpu_fan_speed = FAN_SPEED_MAX;
                fp->system_fan_speed = FAN_SPEED_MAX;
                fp->psupply_fan_on = 1;
@@ -463,11 +428,11 @@ static int kenvctrld(void *__unused)
                if (kthread_should_stop())
                        break;
 
-               for (tp = all_bbc_temps; tp; tp = tp->next) {
+               list_for_each_entry(tp, &all_temps, glob_list) {
                        get_current_temps(tp);
                        analyze_temps(tp, &last_warning_jiffies);
                }
-               for (fp = all_bbc_fans; fp; fp = fp->next)
+               list_for_each_entry(fp, &all_fans, glob_list)
                        maybe_new_fan_speeds(fp);
        }
        printk(KERN_INFO "bbc_envctrl: kenvctrld exiting...\n");
@@ -477,7 +442,8 @@ static int kenvctrld(void *__unused)
        return 0;
 }
 
-static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
+static void attach_one_temp(struct bbc_i2c_bus *bp, struct of_device *op,
+                           int temp_idx)
 {
        struct bbc_cpu_temperature *tp;
 
@@ -485,20 +451,17 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
        if (!tp)
                return;
 
-       tp->client = bbc_i2c_attach(echild);
+       tp->client = bbc_i2c_attach(bp, op);
        if (!tp->client) {
                kfree(tp);
                return;
        }
 
+
        tp->index = temp_idx;
-       {
-               struct bbc_cpu_temperature **tpp = &all_bbc_temps;
-               while (*tpp)
-                       tpp = &((*tpp)->next);
-               tp->next = NULL;
-               *tpp = tp;
-       }
+
+       list_add(&tp->glob_list, &all_temps);
+       list_add(&tp->bp_list, &bp->temps);
 
        /* Tell it to convert once every 5 seconds, clear all cfg
         * bits.
@@ -524,7 +487,8 @@ static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
        tp->fan_todo[FAN_CPU] = FAN_SAME;
 }
 
-static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
+static void attach_one_fan(struct bbc_i2c_bus *bp, struct of_device *op,
+                          int fan_idx)
 {
        struct bbc_fan_control *fp;
 
@@ -532,7 +496,7 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
        if (!fp)
                return;
 
-       fp->client = bbc_i2c_attach(echild);
+       fp->client = bbc_i2c_attach(bp, op);
        if (!fp->client) {
                kfree(fp);
                return;
@@ -540,13 +504,8 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
 
        fp->index = fan_idx;
 
-       {
-               struct bbc_fan_control **fpp = &all_bbc_fans;
-               while (*fpp)
-                       fpp = &((*fpp)->next);
-               fp->next = NULL;
-               *fpp = fp;
-       }
+       list_add(&fp->glob_list, &all_fans);
+       list_add(&fp->bp_list, &bp->fans);
 
        /* The i2c device controlling the fans is write-only.
         * So the only way to keep track of the current power
@@ -563,18 +522,18 @@ static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
        set_fan_speeds(fp);
 }
 
-int bbc_envctrl_init(void)
+int bbc_envctrl_init(struct bbc_i2c_bus *bp)
 {
-       struct linux_ebus_child *echild;
+       struct of_device *op;
        int temp_index = 0;
        int fan_index = 0;
        int devidx = 0;
 
-       while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
-               if (!strcmp(echild->prom_node->name, "temperature"))
-                       attach_one_temp(echild, temp_index++);
-               if (!strcmp(echild->prom_node->name, "fan-control"))
-                       attach_one_fan(echild, fan_index++);
+       while ((op = bbc_i2c_getdev(bp, devidx++)) != NULL) {
+               if (!strcmp(op->node->name, "temperature"))
+                       attach_one_temp(bp, op, temp_index++);
+               if (!strcmp(op->node->name, "fan-control"))
+                       attach_one_fan(bp, op, fan_index++);
        }
        if (temp_index != 0 && fan_index != 0) {
                kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -597,26 +556,22 @@ static void destroy_one_fan(struct bbc_fan_control *fp)
        kfree(fp);
 }
 
-void bbc_envctrl_cleanup(void)
+void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp)
 {
-       struct bbc_cpu_temperature *tp;
-       struct bbc_fan_control *fp;
+       struct bbc_cpu_temperature *tp, *tpos;
+       struct bbc_fan_control *fp, *fpos;
 
        kthread_stop(kenvctrld_task);
 
-       tp = all_bbc_temps;
-       while (tp != NULL) {
-               struct bbc_cpu_temperature *next = tp->next;
+       list_for_each_entry_safe(tp, tpos, &bp->temps, bp_list) {
+               list_del(&tp->bp_list);
+               list_del(&tp->glob_list);
                destroy_one_temp(tp);
-               tp = next;
        }
-       all_bbc_temps = NULL;
 
-       fp = all_bbc_fans;
-       while (fp != NULL) {
-               struct bbc_fan_control *next = fp->next;
+       list_for_each_entry_safe(fp, fpos, &bp->fans, bp_list) {
+               list_del(&fp->bp_list);
+               list_del(&fp->glob_list);
                destroy_one_fan(fp);
-               fp = next;
        }
-       all_bbc_fans = NULL;
 }
index ac8ef2ce07fb6ffd4dc5a4672a4f109a4a402554..f08e169ba1b51a150372753672741df102818591 100644 (file)
@@ -1,8 +1,7 @@
-/* $Id: bbc_i2c.c,v 1.2 2001/04/02 09:59:08 davem Exp $
- * bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
+/* bbc_i2c.c: I2C low-level driver for BBC device on UltraSPARC-III
  *            platforms.
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,9 +13,8 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#include <asm/spitfire.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/bbc.h>
 #include <asm/io.h>
 
  * The second controller also connects to the smartcard reader, if present.
  */
 
-#define NUM_CHILDREN   8
-struct bbc_i2c_bus {
-       struct bbc_i2c_bus              *next;
-       int                             index;
-       spinlock_t                      lock;
-       void                            __iomem *i2c_bussel_reg;
-       void                            __iomem *i2c_control_regs;
-       unsigned char                   own, clock;
-
-       wait_queue_head_t               wq;
-       volatile int                    waiting;
-
-       struct linux_ebus_device        *bus_edev;
-       struct {
-               struct linux_ebus_child *device;
-               int                     client_claimed;
-       } devs[NUM_CHILDREN];
-};
-
-static struct bbc_i2c_bus *all_bbc_i2c;
-
-struct bbc_i2c_client {
-       struct bbc_i2c_bus      *bp;
-       struct linux_ebus_child *echild;
-       int                     bus;
-       int                     address;
-};
-
-static int find_device(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild)
+static void set_device_claimage(struct bbc_i2c_bus *bp, struct of_device *op, int val)
 {
        int i;
 
        for (i = 0; i < NUM_CHILDREN; i++) {
-               if (bp->devs[i].device == echild) {
-                       if (bp->devs[i].client_claimed)
-                               return 0;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child *echild, int val)
-{
-       int i;
-
-       for (i = 0; i < NUM_CHILDREN; i++) {
-               if (bp->devs[i].device == echild) {
+               if (bp->devs[i].device == op) {
                        bp->devs[i].client_claimed = val;
                        return;
                }
@@ -110,61 +66,47 @@ static void set_device_claimage(struct bbc_i2c_bus *bp, struct linux_ebus_child
 #define claim_device(BP,ECHILD)                set_device_claimage(BP,ECHILD,1)
 #define release_device(BP,ECHILD)      set_device_claimage(BP,ECHILD,0)
 
-static struct bbc_i2c_bus *find_bus_for_device(struct linux_ebus_child *echild)
+struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *bp, int index)
 {
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
+       struct of_device *op = NULL;
+       int curidx = 0, i;
 
-       while (bp != NULL) {
-               if (find_device(bp, echild) != 0)
+       for (i = 0; i < NUM_CHILDREN; i++) {
+               if (!(op = bp->devs[i].device))
                        break;
-               bp = bp->next;
+               if (curidx == index)
+                       goto out;
+               op = NULL;
+               curidx++;
        }
 
-       return bp;
-}
-
-struct linux_ebus_child *bbc_i2c_getdev(int index)
-{
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
-       struct linux_ebus_child *echild = NULL;
-       int curidx = 0;
-
-       while (bp != NULL) {
-               struct bbc_i2c_bus *next = bp->next;
-               int i;
-
-               for (i = 0; i < NUM_CHILDREN; i++) {
-                       if (!(echild = bp->devs[i].device))
-                               break;
-                       if (curidx == index)
-                               goto out;
-                       echild = NULL;
-                       curidx++;
-               }
-               bp = next;
-       }
 out:
        if (curidx == index)
-               return echild;
+               return op;
        return NULL;
 }
 
-struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
+struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *op)
 {
-       struct bbc_i2c_bus *bp = find_bus_for_device(echild);
        struct bbc_i2c_client *client;
+       const u32 *reg;
 
-       if (!bp)
-               return NULL;
        client = kzalloc(sizeof(*client), GFP_KERNEL);
        if (!client)
                return NULL;
        client->bp = bp;
-       client->echild = echild;
-       client->bus = echild->resource[0].start;
-       client->address = echild->resource[1].start;
+       client->op = op;
+
+       reg = of_get_property(op->node, "reg", NULL);
+       if (!reg) {
+               kfree(client);
+               return NULL;
+       }
 
-       claim_device(bp, echild);
+       client->bus = reg[0];
+       client->address = reg[1];
+
+       claim_device(bp, op);
 
        return client;
 }
@@ -172,9 +114,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
 void bbc_i2c_detach(struct bbc_i2c_client *client)
 {
        struct bbc_i2c_bus *bp = client->bp;
-       struct linux_ebus_child *echild = client->echild;
+       struct of_device *op = client->op;
 
-       release_device(bp, echild);
+       release_device(bp, op);
        kfree(client);
 }
 
@@ -355,44 +297,43 @@ static void __init reset_one_i2c(struct bbc_i2c_bus *bp)
        writeb(I2C_PCF_IDLE, bp->i2c_control_regs + 0x0);
 }
 
-static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
+static struct bbc_i2c_bus * __init attach_one_i2c(struct of_device *op, int index)
 {
        struct bbc_i2c_bus *bp;
-       struct linux_ebus_child *echild;
+       struct device_node *dp;
        int entry;
 
        bp = kzalloc(sizeof(*bp), GFP_KERNEL);
        if (!bp)
-               return -ENOMEM;
+               return NULL;
 
-       bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
+       bp->i2c_control_regs = of_ioremap(&op->resource[0], 0, 0x2, "bbc_i2c_regs");
        if (!bp->i2c_control_regs)
                goto fail;
 
-       if (edev->num_addrs == 2) {
-               bp->i2c_bussel_reg = ioremap(edev->resource[1].start, 0x1);
-               if (!bp->i2c_bussel_reg)
-                       goto fail;
-       }
+       bp->i2c_bussel_reg = of_ioremap(&op->resource[1], 0, 0x1, "bbc_i2c_bussel");
+       if (!bp->i2c_bussel_reg)
+               goto fail;
 
        bp->waiting = 0;
        init_waitqueue_head(&bp->wq);
-       if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
+       if (request_irq(op->irqs[0], bbc_i2c_interrupt,
                        IRQF_SHARED, "bbc_i2c", bp))
                goto fail;
 
        bp->index = index;
-       bp->bus_edev = edev;
+       bp->op = op;
 
        spin_lock_init(&bp->lock);
-       bp->next = all_bbc_i2c;
-       all_bbc_i2c = bp;
 
        entry = 0;
-       for (echild = edev->children;
-            echild && entry < 8;
-            echild = echild->next, entry++) {
-               bp->devs[entry].device = echild;
+       for (dp = op->node->child;
+            dp && entry < 8;
+            dp = dp->sibling, entry++) {
+               struct of_device *child_op;
+
+               child_op = of_find_device_by_node(dp);
+               bp->devs[entry].device = child_op;
                bp->devs[entry].client_claimed = 0;
        }
 
@@ -406,86 +347,90 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
 
        reset_one_i2c(bp);
 
-       return 0;
+       return bp;
 
 fail:
        if (bp->i2c_bussel_reg)
-               iounmap(bp->i2c_bussel_reg);
+               of_iounmap(&op->resource[1], bp->i2c_bussel_reg, 1);
        if (bp->i2c_control_regs)
-               iounmap(bp->i2c_control_regs);
+               of_iounmap(&op->resource[0], bp->i2c_control_regs, 2);
        kfree(bp);
-       return -EINVAL;
-}
-
-static int __init bbc_present(void)
-{
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "bbc"))
-                               return 1;
-               }
-       }
-       return 0;
+       return NULL;
 }
 
-extern int bbc_envctrl_init(void);
-extern void bbc_envctrl_cleanup(void);
-static void bbc_i2c_cleanup(void);
+extern int bbc_envctrl_init(struct bbc_i2c_bus *bp);
+extern void bbc_envctrl_cleanup(struct bbc_i2c_bus *bp);
 
-static int __init bbc_i2c_init(void)
+static int __devinit bbc_i2c_probe(struct of_device *op,
+                                  const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
+       struct bbc_i2c_bus *bp;
        int err, index = 0;
 
-       if ((tlb_type != cheetah && tlb_type != cheetah_plus) ||
-           !bbc_present())
-               return -ENODEV;
+       bp = attach_one_i2c(op, index);
+       if (!bp)
+               return -EINVAL;
 
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "i2c")) {
-                               if (!attach_one_i2c(edev, index))
-                                       index++;
-                       }
-               }
+       err = bbc_envctrl_init(bp);
+       if (err) {
+               free_irq(op->irqs[0], bp);
+               if (bp->i2c_bussel_reg)
+                       of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+               if (bp->i2c_control_regs)
+                       of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
+               kfree(bp);
+       } else {
+               dev_set_drvdata(&op->dev, bp);
        }
 
-       if (!index)
-               return -ENODEV;
-
-       err = bbc_envctrl_init();
-       if (err)
-               bbc_i2c_cleanup();
        return err;
 }
 
-static void bbc_i2c_cleanup(void)
+static int __devexit bbc_i2c_remove(struct of_device *op)
 {
-       struct bbc_i2c_bus *bp = all_bbc_i2c;
+       struct bbc_i2c_bus *bp = dev_get_drvdata(&op->dev);
+
+       bbc_envctrl_cleanup(bp);
+
+       free_irq(op->irqs[0], bp);
 
-       bbc_envctrl_cleanup();
+       if (bp->i2c_bussel_reg)
+               of_iounmap(&op->resource[0], bp->i2c_bussel_reg, 1);
+       if (bp->i2c_control_regs)
+               of_iounmap(&op->resource[1], bp->i2c_control_regs, 2);
 
-       while (bp != NULL) {
-               struct bbc_i2c_bus *next = bp->next;
+       kfree(bp);
 
-               free_irq(bp->bus_edev->irqs[0], bp);
+       return 0;
+}
 
-               if (bp->i2c_bussel_reg)
-                       iounmap(bp->i2c_bussel_reg);
-               if (bp->i2c_control_regs)
-                       iounmap(bp->i2c_control_regs);
+static const struct of_device_id bbc_i2c_match[] = {
+       {
+               .name = "i2c",
+               .compatible = "SUNW,bbc-i2c",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bbc_i2c_match);
 
-               kfree(bp);
+static struct of_platform_driver bbc_i2c_driver = {
+       .name           = "bbc_i2c",
+       .match_table    = bbc_i2c_match,
+       .probe          = bbc_i2c_probe,
+       .remove         = __devexit_p(bbc_i2c_remove),
+};
 
-               bp = next;
-       }
-       all_bbc_i2c = NULL;
+static int __init bbc_i2c_init(void)
+{
+       return of_register_driver(&bbc_i2c_driver, &of_bus_type);
+}
+
+static void __exit bbc_i2c_exit(void)
+{
+       of_unregister_driver(&bbc_i2c_driver);
 }
 
 module_init(bbc_i2c_init);
-module_exit(bbc_i2c_cleanup);
+module_exit(bbc_i2c_exit);
+
 MODULE_LICENSE("GPL");
index fb01bd17704bdd77f80de016457821033e9b7951..83c4811b7b5e5badda8ff5cb02966db8d4bf24f4 100644 (file)
@@ -1,14 +1,79 @@
-/* $Id: bbc_i2c.h,v 1.2 2001/04/02 09:59:25 davem Exp $ */
 #ifndef _BBC_I2C_H
 #define _BBC_I2C_H
 
-#include <asm/ebus.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/list.h>
 
-struct bbc_i2c_client;
+struct bbc_i2c_client {
+       struct bbc_i2c_bus              *bp;
+       struct of_device                *op;
+       int                             bus;
+       int                             address;
+};
+
+enum fan_action { FAN_SLOWER, FAN_SAME, FAN_FASTER, FAN_FULLBLAST, FAN_STATE_MAX };
+
+struct bbc_cpu_temperature {
+       struct list_head                bp_list;
+       struct list_head                glob_list;
+
+       struct bbc_i2c_client           *client;
+       int                             index;
+
+       /* Current readings, and history. */
+       s8                              curr_cpu_temp;
+       s8                              curr_amb_temp;
+       s8                              prev_cpu_temp;
+       s8                              prev_amb_temp;
+       s8                              avg_cpu_temp;
+       s8                              avg_amb_temp;
+
+       int                             sample_tick;
+
+       enum fan_action                 fan_todo[2];
+#define FAN_AMBIENT    0
+#define FAN_CPU                1
+};
+
+struct bbc_fan_control {
+       struct list_head                bp_list;
+       struct list_head                glob_list;
+
+       struct bbc_i2c_client           *client;
+       int                             index;
+
+       int                             psupply_fan_on;
+       int                             cpu_fan_speed;
+       int                             system_fan_speed;
+};
+
+#define NUM_CHILDREN   8
+
+struct bbc_i2c_bus {
+       struct bbc_i2c_bus              *next;
+       int                             index;
+       spinlock_t                      lock;
+       void                            __iomem *i2c_bussel_reg;
+       void                            __iomem *i2c_control_regs;
+       unsigned char                   own, clock;
+
+       wait_queue_head_t               wq;
+       volatile int                    waiting;
+
+       struct list_head                temps;
+       struct list_head                fans;
+
+       struct of_device                *op;
+       struct {
+               struct of_device        *device;
+               int                     client_claimed;
+       } devs[NUM_CHILDREN];
+};
 
 /* Probing and attachment. */
-extern struct linux_ebus_child *bbc_i2c_getdev(int);
-extern struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *);
+extern struct of_device *bbc_i2c_getdev(struct bbc_i2c_bus *, int);
+extern struct bbc_i2c_client *bbc_i2c_attach(struct bbc_i2c_bus *bp, struct of_device *);
 extern void bbc_i2c_detach(struct bbc_i2c_client *);
 
 /* Register read/write.  NOTE: Blocking! */
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
deleted file mode 100644 (file)
index bba21e0..0000000
+++ /dev/null
@@ -1,1055 +0,0 @@
-/*
- * drivers/sbus/char/bpp.c
- *
- * Copyright (c) 1995 Picture Elements
- *      Stephen Williams (steve@icarus.com)
- *      Gus Baldauf (gbaldauf@ix.netcom.com)
- *
- * Linux/SPARC port by Peter Zaitcev.
- * Integration into SPARC tree by Tom Dyas.
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/ioport.h>
-#include <linux/major.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#if defined(__i386__)
-# include <asm/system.h>
-#endif
-
-#if defined(__sparc__)
-# include <linux/init.h>
-# include <linux/delay.h>         /* udelay() */
-
-# include <asm/oplib.h>           /* OpenProm Library */
-# include <asm/sbus.h>
-#endif
-
-#include <asm/bpp.h>
-
-#define BPP_PROBE_CODE 0x55
-#define BPP_DELAY 100
-
-static const unsigned  BPP_MAJOR = LP_MAJOR;
-static const char *bpp_dev_name = "bpp";
-
-/* When switching from compatibility to a mode where I can read, try
-   the following mode first. */
-
-/* const unsigned char DEFAULT_ECP = 0x10; */
-static const unsigned char DEFAULT_ECP = 0x30;
-static const unsigned char DEFAULT_NIBBLE = 0x00;
-
-/*
- * These are 1284 time constraints, in units of jiffies.
- */
-
-static const unsigned long TIME_PSetup = 1;
-static const unsigned long TIME_PResponse = 6;
-static const unsigned long TIME_IDLE_LIMIT = 2000;
-
-/*
- * One instance per supported subdevice...
- */
-# define BPP_NO 3
-
-enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
-
-struct inst {
-      unsigned present  : 1; /* True if the hardware exists */
-      unsigned enhanced : 1; /* True if the hardware in "enhanced" */
-      unsigned opened   : 1; /* True if the device is opened already */
-      unsigned run_flag : 1; /* True if waiting for a repeate byte */
-
-      unsigned char direction; /* 0 --> out, 0x20 --> IN */
-      unsigned char pp_state; /* State of host controlled pins. */
-      enum IEEE_Mode mode;
-
-      unsigned char run_length;
-      unsigned char repeat_byte;
-};
-
-static struct inst instances[BPP_NO];
-
-#if defined(__i386__)
-
-static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
-
-/*
- * These are for data access.
- * Control lines accesses are hidden in set_bits() and get_bits().
- * The exception is the probe procedure, which is system-dependent.
- */
-#define bpp_outb_p(data, base)  outb_p((data), (base))
-#define bpp_inb(base)  inb(base)
-#define bpp_inb_p(base)  inb_p(base)
-
-/*
- * This method takes the pin values mask and sets the hardware pins to
- * the requested value: 1 == high voltage, 0 == low voltage. This
- * burries the annoying PC bit inversion and preserves the direction
- * flag.
- */
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      unsigned char bits = instances[minor].direction;  /* == 0x20 */
-
-      if (! (pins & BPP_PP_nStrobe))   bits |= 1;
-      if (! (pins & BPP_PP_nAutoFd))   bits |= 2;
-      if (   pins & BPP_PP_nInit)      bits |= 4;
-      if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
-
-      instances[minor].pp_state = bits;
-
-      outb_p(bits, base_addrs[minor]+2);
-}
-
-static unsigned short get_pins(unsigned minor)
-{
-      unsigned short bits = 0;
-
-      unsigned value = instances[minor].pp_state;
-      if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
-      if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
-      if (value & 0x04)     bits |= BPP_PP_nInit;
-      if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
-
-      value = inb_p(base_addrs[minor]+1);
-      if (value & 0x08)     bits |= BPP_GP_nFault;
-      if (value & 0x10)     bits |= BPP_GP_Select;
-      if (value & 0x20)     bits |= BPP_GP_PError;
-      if (value & 0x40)     bits |= BPP_GP_nAck;
-      if (! (value & 0x80)) bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __i386__ */
-
-#if defined(__sparc__)
-
-/*
- * Register block
- */
-      /* DMA registers */
-#define BPP_CSR      0x00
-#define BPP_ADDR     0x04
-#define BPP_BCNT     0x08
-#define BPP_TST_CSR  0x0C
-      /* Parallel Port registers */
-#define BPP_HCR      0x10
-#define BPP_OCR      0x12
-#define BPP_DR       0x14
-#define BPP_TCR      0x15
-#define BPP_OR       0x16
-#define BPP_IR       0x17
-#define BPP_ICR      0x18
-#define BPP_SIZE     0x1A
-
-/* BPP_CSR.  Bits of type RW1 are cleared with writing '1'. */
-#define P_DEV_ID_MASK   0xf0000000      /* R   */
-#define P_DEV_ID_ZEBRA  0x40000000
-#define P_DEV_ID_L64854 0xa0000000      /*      == NCR 89C100+89C105. Pity. */
-#define P_NA_LOADED     0x08000000      /* R    NA wirtten but was not used */
-#define P_A_LOADED      0x04000000      /* R    */
-#define P_DMA_ON        0x02000000      /* R    DMA is not disabled */
-#define P_EN_NEXT       0x01000000      /* RW   */
-#define P_TCI_DIS       0x00800000      /* RW   TCI forbidden from interrupts */
-#define P_DIAG          0x00100000      /* RW   Disables draining and resetting
-                                                of P-FIFO on loading of P_ADDR*/
-#define P_BURST_SIZE    0x000c0000      /* RW   SBus burst size */
-#define P_BURST_8       0x00000000
-#define P_BURST_4       0x00040000
-#define P_BURST_1       0x00080000      /*      "No burst" write */
-#define P_TC            0x00004000      /* RW1  Term Count, can be cleared when
-                                           P_EN_NEXT=1 */
-#define P_EN_CNT        0x00002000      /* RW   */
-#define P_EN_DMA        0x00000200      /* RW   */
-#define P_WRITE         0x00000100      /* R    DMA dir, 1=to ram, 0=to port */
-#define P_RESET         0x00000080      /* RW   */
-#define P_SLAVE_ERR     0x00000040      /* RW1  Access size error */
-#define P_INVALIDATE    0x00000020      /* W    Drop P-FIFO */
-#define P_INT_EN        0x00000010      /* RW   OK to P_INT_PEND||P_ERR_PEND */
-#define P_DRAINING      0x0000000c      /* R    P-FIFO is draining to memory */
-#define P_ERR_PEND      0x00000002      /* R    */
-#define P_INT_PEND      0x00000001      /* R    */
-
-/* BPP_HCR. Time is in increments of SBus clock. */
-#define P_HCR_TEST      0x8000      /* Allows buried counters to be read */
-#define P_HCR_DSW       0x7f00      /* Data strobe width (in ticks) */
-#define P_HCR_DDS       0x007f      /* Data setup before strobe (in ticks) */
-
-/* BPP_OCR. */
-#define P_OCR_MEM_CLR   0x8000
-#define P_OCR_DATA_SRC  0x4000      /* )                  */
-#define P_OCR_DS_DSEL   0x2000      /* )  Bidirectional      */
-#define P_OCR_BUSY_DSEL 0x1000      /* )    selects            */
-#define P_OCR_ACK_DSEL  0x0800      /* )                  */
-#define P_OCR_EN_DIAG   0x0400
-#define P_OCR_BUSY_OP   0x0200      /* Busy operation */
-#define P_OCR_ACK_OP    0x0100      /* Ack operation */
-#define P_OCR_SRST      0x0080      /* Reset state machines. Not selfcleaning. */
-#define P_OCR_IDLE      0x0008      /* PP data transfer state machine is idle */
-#define P_OCR_V_ILCK    0x0002      /* Versatec faded. Zebra only. */
-#define P_OCR_EN_VER    0x0001      /* Enable Versatec (0 - enable). Zebra only. */
-
-/* BPP_TCR */
-#define P_TCR_DIR       0x08
-#define P_TCR_BUSY      0x04
-#define P_TCR_ACK       0x02
-#define P_TCR_DS        0x01        /* Strobe */
-
-/* BPP_OR */
-#define P_OR_V3         0x20        /* )                 */
-#define P_OR_V2         0x10        /* ) on Zebra only   */
-#define P_OR_V1         0x08        /* )                 */
-#define P_OR_INIT       0x04
-#define P_OR_AFXN       0x02        /* Auto Feed */
-#define P_OR_SLCT_IN    0x01
-
-/* BPP_IR */
-#define P_IR_PE         0x04
-#define P_IR_SLCT       0x02
-#define P_IR_ERR        0x01
-
-/* BPP_ICR */
-#define P_DS_IRQ        0x8000      /* RW1  */
-#define P_ACK_IRQ       0x4000      /* RW1  */
-#define P_BUSY_IRQ      0x2000      /* RW1  */
-#define P_PE_IRQ        0x1000      /* RW1  */
-#define P_SLCT_IRQ      0x0800      /* RW1  */
-#define P_ERR_IRQ       0x0400      /* RW1  */
-#define P_DS_IRQ_EN     0x0200      /* RW   Always on rising edge */
-#define P_ACK_IRQ_EN    0x0100      /* RW   Always on rising edge */
-#define P_BUSY_IRP      0x0080      /* RW   1= rising edge */
-#define P_BUSY_IRQ_EN   0x0040      /* RW   */
-#define P_PE_IRP        0x0020      /* RW   1= rising edge */
-#define P_PE_IRQ_EN     0x0010      /* RW   */
-#define P_SLCT_IRP      0x0008      /* RW   1= rising edge */
-#define P_SLCT_IRQ_EN   0x0004      /* RW   */
-#define P_ERR_IRP       0x0002      /* RW1  1= rising edge */
-#define P_ERR_IRQ_EN    0x0001      /* RW   */
-
-static void __iomem *base_addrs[BPP_NO];
-
-#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR)
-#define bpp_inb_p(base)                sbus_readb((base) + BPP_DR)
-#define bpp_inb(base)          sbus_readb((base) + BPP_DR)
-
-static void set_pins(unsigned short pins, unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned char bits_tcr = 0, bits_or = 0;
-
-      if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR;
-      if (   pins & BPP_PP_nStrobe)          bits_tcr |= P_TCR_DS;
-
-      if (   pins & BPP_PP_nAutoFd)          bits_or |= P_OR_AFXN;
-      if (! (pins & BPP_PP_nInit))           bits_or |= P_OR_INIT;
-      if (! (pins & BPP_PP_nSelectIn))       bits_or |= P_OR_SLCT_IN;
-
-      sbus_writeb(bits_or, base + BPP_OR);
-      sbus_writeb(bits_tcr, base + BPP_TCR);
-}
-
-/*
- * i386 people read output pins from a software image.
- * We may get them back from hardware.
- * Again, inversion of pins must he buried here.
- */
-static unsigned short get_pins(unsigned minor)
-{
-      void __iomem *base = base_addrs[minor];
-      unsigned short bits = 0;
-      unsigned value_tcr = sbus_readb(base + BPP_TCR);
-      unsigned value_ir = sbus_readb(base + BPP_IR);
-      unsigned value_or = sbus_readb(base + BPP_OR);
-
-      if (value_tcr & P_TCR_DS)         bits |= BPP_PP_nStrobe;
-      if (value_or & P_OR_AFXN)         bits |= BPP_PP_nAutoFd;
-      if (! (value_or & P_OR_INIT))     bits |= BPP_PP_nInit;
-      if (! (value_or & P_OR_SLCT_IN))  bits |= BPP_PP_nSelectIn;
-
-      if (value_ir & P_IR_ERR)          bits |= BPP_GP_nFault;
-      if (! (value_ir & P_IR_SLCT))     bits |= BPP_GP_Select;
-      if (! (value_ir & P_IR_PE))       bits |= BPP_GP_PError;
-      if (! (value_tcr & P_TCR_ACK))    bits |= BPP_GP_nAck;
-      if (value_tcr & P_TCR_BUSY)       bits |= BPP_GP_Busy;
-
-      return bits;
-}
-
-#endif /* __sparc__ */
-
-static void snooze(unsigned long snooze_time, unsigned minor)
-{
-       schedule_timeout_uninterruptible(snooze_time + 1);
-}
-
-static int wait_for(unsigned short set, unsigned short clr,
-               unsigned long delay, unsigned minor)
-{
-      unsigned short pins = get_pins(minor);
-
-      unsigned long extime = 0;
-
-      /*
-       * Try a real fast scan for the first jiffy, in case the device
-       * responds real good. The first while loop guesses an expire
-       * time accounting for possible wraparound of jiffies.
-       */
-      while (time_after_eq(jiffies, extime)) extime = jiffies + 1;
-      while ( (time_before(jiffies, extime))
-              && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-            pins = get_pins(minor);
-      }
-
-      delay -= 1;
-
-      /*
-       * If my delay expired or the pins are still not where I want
-       * them, then resort to using the timer and greatly reduce my
-       * sample rate. If the peripheral is going to be slow, this will
-       * give the CPU up to some more worthy process.
-       */
-      while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) {
-
-            snooze(1, minor);
-            pins = get_pins(minor);
-            delay -= 1;
-      }
-
-      if (delay == 0) return -1;
-      else return pins;
-}
-
-/*
- * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An
- * errno means something broke, and I do not yet know how to fix it.
- */
-static int negotiate(unsigned char mode, unsigned minor)
-{
-      int rc;
-      unsigned short pins = get_pins(minor);
-      if (pins & BPP_PP_nSelectIn) return -EIO;
-
-
-        /* Event 0: Write the mode to the data lines */
-      bpp_outb_p(mode, base_addrs[minor]);
-
-      snooze(TIME_PSetup, minor);
-
-        /* Event 1: Strobe the mode code into the peripheral */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 2: Peripheral responds as a 1284 device. */
-      rc = wait_for(BPP_GP_PError|BPP_GP_Select|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PResponse,
-                minor);
-
-      if (rc == -1) return -ETIMEDOUT;
-
-        /* Event 3: latch extensibility request */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nInit, minor);
-
-        /* ... quick nap while peripheral ponders the byte i'm sending...*/
-      snooze(1, minor);
-
-        /* Event 4: restore strobe, to ACK peripheral's response. */
-      set_pins(BPP_PP_nSelectIn|BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Event 6: Peripheral latches response bits */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PSetup+TIME_PResponse, minor);
-      if (rc == -1) return -EIO;
-
-        /* A 1284 device cannot refuse nibble mode */
-      if (mode == DEFAULT_NIBBLE) return 0;
-
-      if (pins & BPP_GP_Select) return 0;
-
-      return -EPROTONOSUPPORT;
-}
-
-static int terminate(unsigned minor)
-{
-      int rc;
-
-        /* Event 22: Request termination of 1284 mode */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Wait for Events 23 and 24: ACK termination request. */
-      rc = wait_for(BPP_GP_Busy|BPP_GP_nFault,
-                BPP_GP_nAck,
-                TIME_PSetup+TIME_PResponse,
-                minor);
-
-      instances[minor].direction = 0;
-      instances[minor].mode = COMPATIBILITY;
-
-      if (rc == -1) {
-          return -EIO;
-      }
-
-        /* Event 25: Handshake by lowering nAutoFd */
-      set_pins(BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-        /* Event 26: Peripheral wiggles lines... */
-
-        /* Event 27: Peripheral sets nAck HIGH to ack handshake */
-      rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-      if (rc == -1) {
-          set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-          return -EIO;
-      }
-
-        /* Event 28: Finish phase by raising nAutoFd */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, minor);
-
-      return 0;
-}
-
-static DEFINE_SPINLOCK(bpp_open_lock);
-
-/*
- * Allow only one process to open the device at a time.
- */
-static int bpp_open(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-      int ret;
-
-      lock_kernel();
-      spin_lock(&bpp_open_lock);
-      ret = 0;
-      if (minor >= BPP_NO) {
-             ret = -ENODEV;
-      } else {
-             if (! instances[minor].present) {
-                     ret = -ENODEV;
-             } else {
-                     if (instances[minor].opened) 
-                             ret = -EBUSY;
-                     else
-                             instances[minor].opened = 1;
-             }
-      }
-      spin_unlock(&bpp_open_lock);
-      unlock_kernel();
-
-      return ret;
-}
-
-/*
- * When the process closes the device, this method is called to clean
- * up and reset the hardware. Always leave the device in compatibility
- * mode as this is a reasonable place to clean up from messes made by
- * ioctls, or other mayhem.
- */
-static int bpp_release(struct inode *inode, struct file *f)
-{
-      unsigned minor = iminor(inode);
-
-      spin_lock(&bpp_open_lock);
-      instances[minor].opened = 0;
-
-      if (instances[minor].mode != COMPATIBILITY)
-             terminate(minor);
-
-      spin_unlock(&bpp_open_lock);
-
-      return 0;
-}
-
-static long read_nibble(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining = cnt;
-      long rc;
-
-      while (remaining > 0) {
-          unsigned char byte = 0;
-          int pins;
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (pins == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x01;
-          if (pins & BPP_GP_Select) byte |= 0x02;
-          if (pins & BPP_GP_PError) byte |= 0x04;
-          if (pins & BPP_GP_Busy)   byte |= 0x08;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-
-          /* Event 7: request nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe, minor);
-
-          /* Wait for event 9: Peripher strobes first nibble */
-          pins = wait_for(0, BPP_GP_nAck, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          /* Event 10: I handshake nibble */
-          set_pins(BPP_PP_nSelectIn|BPP_PP_nStrobe|BPP_PP_nAutoFd, minor);
-          if (pins & BPP_GP_nFault) byte |= 0x10;
-          if (pins & BPP_GP_Select) byte |= 0x20;
-          if (pins & BPP_GP_PError) byte |= 0x40;
-          if (pins & BPP_GP_Busy)   byte |= 0x80;
-
-          if (put_user(byte, c))
-                 return -EFAULT;
-          c += 1;
-          remaining -= 1;
-
-          /* Wait for event 11: Peripheral handshakes nibble */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-      }
-
-      return cnt - remaining;
-}
-
-static long read_ecp(unsigned minor, char __user *c, unsigned long cnt)
-{
-      unsigned long remaining;
-      long rc;
-
-        /* Turn ECP mode from forward to reverse if needed. */
-      if (! instances[minor].direction) {
-          unsigned short pins = get_pins(minor);
-
-            /* Event 38: Turn the bus around */
-          instances[minor].direction = 0x20;
-          pins &= ~BPP_PP_nAutoFd;
-          set_pins(pins, minor);
-
-            /* Event 39: Set pins for reverse mode. */
-          snooze(TIME_PSetup, minor);
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 40: Peripheral ready to be strobed */
-          rc = wait_for(0, BPP_GP_PError, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-      }
-
-      remaining = cnt;
-
-      while (remaining > 0) {
-
-            /* If there is a run length for a repeated byte, repeat */
-            /* that byte a few times. */
-          if (instances[minor].run_length && !instances[minor].run_flag) {
-
-              char buffer[128];
-              unsigned idx;
-              unsigned repeat = remaining < instances[minor].run_length
-                                     ? remaining
-                               : instances[minor].run_length;
-
-              for (idx = 0 ;  idx < repeat ;  idx += 1)
-                buffer[idx] = instances[minor].repeat_byte;
-
-              if (copy_to_user(c, buffer, repeat))
-                     return -EFAULT;
-              remaining -= repeat;
-              c += repeat;
-              instances[minor].run_length -= repeat;
-          }
-
-          if (remaining == 0) break;
-
-
-            /* Wait for Event 43: Data active on the bus. */
-          rc = wait_for(0, BPP_GP_nAck, TIME_IDLE_LIMIT, minor);
-          if (rc == -1) break;
-
-          if (rc & BPP_GP_Busy) {
-                /* OK, this is data. read it in. */
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (put_user(byte, c))
-                     return -EFAULT;
-              c += 1;
-              remaining -= 1;
-
-              if (instances[minor].run_flag) {
-                  instances[minor].repeat_byte = byte;
-                  instances[minor].run_flag = 0;
-              }
-
-          } else {
-              unsigned char byte = bpp_inb(base_addrs[minor]);
-              if (byte & 0x80) {
-                  printk("bpp%d: "
-                         "Ignoring ECP channel %u from device.\n",
-                         minor, byte & 0x7f);
-              } else {
-                  instances[minor].run_length = byte;
-                  instances[minor].run_flag = 1;
-              }
-          }
-
-            /* Event 44: I got it. */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nAutoFd|BPP_PP_nSelectIn, minor);
-
-            /* Wait for event 45: peripheral handshake */
-          rc = wait_for(BPP_GP_nAck, 0, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-             /* Event 46: Finish handshake */
-          set_pins(BPP_PP_nStrobe|BPP_PP_nSelectIn, minor);
-
-      }
-
-
-      return cnt - remaining;
-}
-
-static ssize_t bpp_read(struct file *f, char __user *c, size_t cnt, loff_t * ppos)
-{
-      long rc;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        default:
-          if (instances[minor].mode != COMPATIBILITY)
-            terminate(minor);
-
-          if (instances[minor].enhanced) {
-              /* For now, do all reads with ECP-RLE mode */
-              unsigned short pins;
-
-              rc = negotiate(DEFAULT_ECP, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = ECP_RLE;
-
-              /* Event 30: set nAutoFd low to setup for ECP mode */
-              pins = get_pins(minor);
-              pins &= ~BPP_PP_nAutoFd;
-              set_pins(pins, minor);
-
-              /* Wait for Event 31: peripheral ready */
-              rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-              if (rc == -1) return -ETIMEDOUT;
-
-              rc = read_ecp(minor, c, cnt);
-
-          } else {
-              rc = negotiate(DEFAULT_NIBBLE, minor);
-              if (rc < 0) break;
-
-              instances[minor].mode = NIBBLE;
-
-              rc = read_nibble(minor, c, cnt);
-          }
-          break;
-
-        case NIBBLE:
-          rc = read_nibble(minor, c, cnt);
-          break;
-
-        case ECP:
-        case ECP_RLE:
-          rc = read_ecp(minor, c, cnt);
-          break;
-
-      }
-
-
-      return rc;
-}
-
-/*
- * Compatibility mode handshaking is a matter of writing data,
- * strobing it, and waiting for the printer to stop being busy.
- */
-static long write_compat(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      long rc;
-      unsigned short pins = get_pins(minor);
-
-      unsigned long remaining = cnt;
-
-
-      while (remaining > 0) {
-            unsigned char byte;
-
-            if (get_user(byte, c))
-                   return -EFAULT;
-            c += 1;
-
-            rc = wait_for(BPP_GP_nAck, BPP_GP_Busy, TIME_IDLE_LIMIT, minor);
-            if (rc == -1) return -ETIMEDOUT;
-
-            bpp_outb_p(byte, base_addrs[minor]);
-            remaining -= 1;
-          /* snooze(1, minor); */
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nStrobe;
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write data using ECP mode. Watch out that the port may be set up
- * for reading. If so, turn the port around.
- */
-static long write_ecp(unsigned minor, const char __user *c, unsigned long cnt)
-{
-      unsigned short pins = get_pins(minor);
-      unsigned long remaining = cnt;
-
-      if (instances[minor].direction) {
-          int rc;
-
-            /* Event 47 Request bus be turned around */
-          pins |= BPP_PP_nInit;
-          set_pins(pins, minor);
-
-            /* Wait for Event 49: Peripheral relinquished bus */
-          rc = wait_for(BPP_GP_PError, 0, TIME_PResponse, minor);
-
-          pins |= BPP_PP_nAutoFd;
-          instances[minor].direction = 0;
-          set_pins(pins, minor);
-      }
-
-      while (remaining > 0) {
-          unsigned char byte;
-          int rc;
-
-          if (get_user(byte, c))
-                 return -EFAULT;
-
-          rc = wait_for(0, BPP_GP_Busy, TIME_PResponse, minor);
-          if (rc == -1) return -ETIMEDOUT;
-
-          c += 1;
-
-          bpp_outb_p(byte, base_addrs[minor]);
-
-          pins &= ~BPP_PP_nStrobe;
-          set_pins(pins, minor);
-
-          pins |= BPP_PP_nStrobe;
-          rc = wait_for(BPP_GP_Busy, 0, TIME_PResponse, minor);
-          if (rc == -1) return -EIO;
-
-          set_pins(pins, minor);
-      }
-
-      return cnt - remaining;
-}
-
-/*
- * Write to the peripheral. Be sensitive of the current mode. If I'm
- * in a mode that can be turned around (ECP) then just do
- * that. Otherwise, terminate and do my writing in compat mode. This
- * is the safest course as any device can handle it.
- */
-static ssize_t bpp_write(struct file *f, const char __user *c, size_t cnt, loff_t * ppos)
-{
-      long errno = 0;
-      unsigned minor = iminor(f->f_path.dentry->d_inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-      switch (instances[minor].mode) {
-
-        case ECP:
-        case ECP_RLE:
-          errno = write_ecp(minor, c, cnt);
-          break;
-        case COMPATIBILITY:
-          errno = write_compat(minor, c, cnt);
-          break;
-        default:
-          terminate(minor);
-          errno = write_compat(minor, c, cnt);
-      }
-
-      return errno;
-}
-
-static int bpp_ioctl(struct inode *inode, struct file *f, unsigned int cmd,
-                unsigned long arg)
-{
-      int errno = 0;
-
-      unsigned minor = iminor(inode);
-      if (minor >= BPP_NO) return -ENODEV;
-      if (!instances[minor].present) return -ENODEV;
-
-
-      switch (cmd) {
-
-        case BPP_PUT_PINS:
-          set_pins(arg, minor);
-          break;
-
-        case BPP_GET_PINS:
-          errno = get_pins(minor);
-          break;
-
-        case BPP_PUT_DATA:
-          bpp_outb_p(arg, base_addrs[minor]);
-          break;
-
-        case BPP_GET_DATA:
-          errno = bpp_inb_p(base_addrs[minor]);
-          break;
-
-        case BPP_SET_INPUT:
-          if (arg)
-            if (instances[minor].enhanced) {
-                unsigned short bits = get_pins(minor);
-                instances[minor].direction = 0x20;
-                set_pins(bits, minor);
-            } else {
-                errno = -ENOTTY;
-            }
-          else {
-              unsigned short bits = get_pins(minor);
-              instances[minor].direction = 0x00;
-              set_pins(bits, minor);
-          }
-          break;
-
-        default:
-            errno = -EINVAL;
-      }
-
-      return errno;
-}
-
-static const struct file_operations bpp_fops = {
-       .owner =        THIS_MODULE,
-       .read =         bpp_read,
-       .write =        bpp_write,
-       .ioctl =        bpp_ioctl,
-       .open =         bpp_open,
-       .release =      bpp_release,
-};
-
-#if defined(__i386__)
-
-#define collectLptPorts()  {}
-
-static void probeLptPort(unsigned idx)
-{
-      unsigned int testvalue;
-      const unsigned short lpAddr = base_addrs[idx];
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-      if (!request_region(lpAddr,3, bpp_dev_name)) return;
-
-      /*
-       * First, make sure the instance exists. Do this by writing to
-       * the data latch and reading the value back. If the port *is*
-       * present, test to see if it supports extended-mode
-       * operation. This will be required for IEEE1284 reverse
-       * transfers.
-       */
-
-      outb_p(BPP_PROBE_CODE, lpAddr);
-      for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-            ;
-      testvalue = inb_p(lpAddr);
-      if (testvalue == BPP_PROBE_CODE) {
-            unsigned save;
-            instances[idx].present = 1;
-
-            save = inb_p(lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(save|0x20, lpAddr+2);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            outb_p(~BPP_PROBE_CODE, lpAddr);
-            for (testvalue=0; testvalue<BPP_DELAY; testvalue++)
-                  ;
-            testvalue = inb_p(lpAddr);
-            if ((testvalue&0xff) == (0xff&~BPP_PROBE_CODE))
-                  instances[idx].enhanced = 0;
-            else
-                  instances[idx].enhanced = 1;
-            outb_p(save, lpAddr+2);
-      }
-      else {
-            release_region(lpAddr,3);
-      }
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      printk("bpp%d: Port at 0x%03x: Enhanced mode %s\n", idx, base_addrs[idx],
-            instances[idx].enhanced? "SUPPORTED" : "UNAVAILABLE");
-}
-
-static inline void freeLptPort(int idx)
-{
-      release_region(base_addrs[idx], 3);
-}
-
-#endif
-
-#if defined(__sparc__)
-
-static void __iomem *map_bpp(struct sbus_dev *dev, int idx)
-{
-      return sbus_ioremap(&dev->resource[0], 0, BPP_SIZE, "bpp");
-}
-
-static int collectLptPorts(void)
-{
-       struct sbus_bus *bus;
-       struct sbus_dev *dev;
-       int count;
-
-       count = 0;
-       for_all_sbusdev(dev, bus) {
-               if (strcmp(dev->prom_name, "SUNW,bpp") == 0) {
-                       if (count >= BPP_NO) {
-                               printk(KERN_NOTICE
-                                      "bpp: More than %d bpp ports,"
-                                      " rest is ignored\n", BPP_NO);
-                               return count;
-                       }
-                       base_addrs[count] = map_bpp(dev, count);
-                       count++;
-               }
-       }
-       return count;
-}
-
-static void probeLptPort(unsigned idx)
-{
-      void __iomem *rp = base_addrs[idx];
-      __u32 csr;
-      char *brand;
-
-      instances[idx].present = 0;
-      instances[idx].enhanced = 0;
-      instances[idx].direction = 0;
-      instances[idx].mode = COMPATIBILITY;
-      instances[idx].run_length = 0;
-      instances[idx].run_flag = 0;
-
-      if (!rp) return;
-
-      instances[idx].present = 1;
-      instances[idx].enhanced = 1;   /* Sure */
-
-      csr = sbus_readl(rp + BPP_CSR);
-      if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-            udelay(20);
-            csr = sbus_readl(rp + BPP_CSR);
-            if ((csr & P_DRAINING) != 0 && (csr & P_ERR_PEND) == 0) {
-                  printk("bpp%d: DRAINING still active (0x%08x)\n", idx, csr);
-            }
-      }
-      printk("bpp%d: reset with 0x%08x ..", idx, csr);
-      sbus_writel((csr | P_RESET) & ~P_INT_EN, rp + BPP_CSR);
-      udelay(500);
-      sbus_writel(sbus_readl(rp + BPP_CSR) & ~P_RESET, rp + BPP_CSR);
-      csr = sbus_readl(rp + BPP_CSR);
-      printk(" done with csr=0x%08x ocr=0x%04x\n",
-         csr, sbus_readw(rp + BPP_OCR));
-
-      switch (csr & P_DEV_ID_MASK) {
-      case P_DEV_ID_ZEBRA:
-            brand = "Zebra";
-            break;
-      case P_DEV_ID_L64854:
-            brand = "DMA2";
-            break;
-      default:
-            brand = "Unknown";
-      }
-      printk("bpp%d: %s at %p\n", idx, brand, rp);
-
-      /*
-       * Leave the port in compat idle mode.
-       */
-      set_pins(BPP_PP_nAutoFd|BPP_PP_nStrobe|BPP_PP_nInit, idx);
-
-      return;
-}
-
-static inline void freeLptPort(int idx)
-{
-      sbus_iounmap(base_addrs[idx], BPP_SIZE);
-}
-
-#endif
-
-static int __init bpp_init(void)
-{
-       int rc;
-       unsigned idx;
-
-       rc = collectLptPorts();
-       if (rc == 0)
-               return -ENODEV;
-
-       rc = register_chrdev(BPP_MAJOR, bpp_dev_name, &bpp_fops);
-       if (rc < 0)
-               return rc;
-
-       for (idx = 0; idx < BPP_NO; idx++) {
-               instances[idx].opened = 0;
-               probeLptPort(idx);
-       }
-
-       return 0;
-}
-
-static void __exit bpp_cleanup(void)
-{
-       unsigned idx;
-
-       unregister_chrdev(BPP_MAJOR, bpp_dev_name);
-
-       for (idx = 0;  idx < BPP_NO; idx++) {
-               if (instances[idx].present)
-                       freeLptPort(idx);
-       }
-}
-
-module_init(bpp_init);
-module_exit(bpp_cleanup);
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
deleted file mode 100644 (file)
index 23abfdf..0000000
+++ /dev/null
@@ -1,858 +0,0 @@
-/* cpwatchdog.c - driver implementation for hardware watchdog
- * timers found on Sun Microsystems CP1400 and CP1500 boards.
- *
- * This device supports both the generic Linux watchdog 
- * interface and Solaris-compatible ioctls as best it is
- * able.
- *
- * NOTE:       CP1400 systems appear to have a defective intr_mask
- *                     register on the PLD, preventing the disabling of
- *                     timer interrupts.  We use a timer to periodically 
- *                     reset 'stopped' watchdogs on affected platforms.
- *
- * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/errno.h>
-#include <linux/major.h>
-#include <linux/init.h>
-#include <linux/miscdevice.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/smp_lock.h>
-#include <linux/io.h>
-#include <asm/irq.h>
-#include <asm/ebus.h>
-#include <asm/oplib.h>
-#include <asm/uaccess.h>
-
-#include <asm/watchdog.h>
-
-#define WD_OBPNAME     "watchdog"
-#define WD_BADMODEL "SUNW,501-5336"
-#define WD_BTIMEOUT    (jiffies + (HZ * 1000))
-#define WD_BLIMIT      0xFFFF
-
-#define WD0_DEVNAME "watchdog0"
-#define WD1_DEVNAME "watchdog1"
-#define WD2_DEVNAME "watchdog2"
-
-#define WD0_MINOR      212
-#define WD1_MINOR      213     
-#define WD2_MINOR      214     
-
-
-/* Internal driver definitions
- */
-#define WD0_ID                 0               /* Watchdog0                                            */
-#define WD1_ID                 1               /* Watchdog1                                            */
-#define WD2_ID                 2               /* Watchdog2                                            */
-#define WD_NUMDEVS             3               /* Device contains 3 timers                     */
-
-#define WD_INTR_OFF            0               /* Interrupt disable value                      */
-#define WD_INTR_ON             1               /* Interrupt enable value                       */
-
-#define WD_STAT_INIT   0x01    /* Watchdog timer is initialized        */
-#define WD_STAT_BSTOP  0x02    /* Watchdog timer is brokenstopped      */
-#define WD_STAT_SVCD   0x04    /* Watchdog interrupt occurred          */
-
-/* Register value definitions
- */
-#define WD0_INTR_MASK  0x01    /* Watchdog device interrupt masks      */
-#define WD1_INTR_MASK  0x02
-#define WD2_INTR_MASK  0x04
-
-#define WD_S_RUNNING   0x01    /* Watchdog device status running       */
-#define WD_S_EXPIRED   0x02    /* Watchdog device status expired       */
-
-/* Sun uses Altera PLD EPF8820ATC144-4 
- * providing three hardware watchdogs:
- *
- *     1) RIC - sends an interrupt when triggered
- *     2) XIR - asserts XIR_B_RESET when triggered, resets CPU
- *     3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
- *
- *** Timer register block definition (struct wd_timer_regblk)
- *
- * dcntr and limit registers (halfword access):      
- * -------------------
- * | 15 | ...| 1 | 0 |
- * -------------------
- * |-  counter val  -|
- * -------------------
- * dcntr -     Current 16-bit downcounter value.
- *                     When downcounter reaches '0' watchdog expires.
- *                     Reading this register resets downcounter with 'limit' value.
- * limit -     16-bit countdown value in 1/10th second increments.
- *                     Writing this register begins countdown with input value.
- *                     Reading from this register does not affect counter.
- * NOTES:      After watchdog reset, dcntr and limit contain '1'
- *
- * status register (byte access):
- * ---------------------------
- * | 7 | ... | 2 |  1  |  0  |
- * --------------+------------
- * |-   UNUSED  -| EXP | RUN |
- * ---------------------------
- * status-     Bit 0 - Watchdog is running
- *                     Bit 1 - Watchdog has expired
- *
- *** PLD register block definition (struct wd_pld_regblk)
- *
- * intr_mask register (byte access):
- * ---------------------------------
- * | 7 | ... | 3 |  2  |  1  |  0  |
- * +-------------+------------------
- * |-   UNUSED  -| WD3 | WD2 | WD1 |
- * ---------------------------------
- * WD3 -  1 == Interrupt disabled for watchdog 3
- * WD2 -  1 == Interrupt disabled for watchdog 2
- * WD1 -  1 == Interrupt disabled for watchdog 1
- *
- * pld_status register (byte access):
- * UNKNOWN, MAGICAL MYSTERY REGISTER
- *
- */
-#define WD_TIMER_REGSZ 16
-#define WD0_OFF                0
-#define WD1_OFF                (WD_TIMER_REGSZ * 1)
-#define WD2_OFF                (WD_TIMER_REGSZ * 2)
-#define PLD_OFF                (WD_TIMER_REGSZ * 3)
-
-#define WD_DCNTR       0x00
-#define WD_LIMIT       0x04
-#define WD_STATUS      0x08
-
-#define PLD_IMASK      (PLD_OFF + 0x00)
-#define PLD_STATUS     (PLD_OFF + 0x04)
-
-/* Individual timer structure 
- */
-struct wd_timer {
-       __u16                   timeout;
-       __u8                    intr_mask;
-       unsigned char           runstatus;
-       void __iomem            *regs;
-};
-
-/* Device structure
- */
-struct wd_device {
-       int                             irq;
-       spinlock_t              lock;
-       unsigned char   isbaddoggie;    /* defective PLD */
-       unsigned char   opt_enable;
-       unsigned char   opt_reboot;
-       unsigned short  opt_timeout;
-       unsigned char   initialized;
-       struct wd_timer watchdog[WD_NUMDEVS];
-       void __iomem    *regs;
-};
-
-static struct wd_device wd_dev = { 
-               0, __SPIN_LOCK_UNLOCKED(wd_dev.lock), 0, 0, 0, 0,
-};
-
-static struct timer_list wd_timer;
-
-static int wd0_timeout = 0;
-static int wd1_timeout = 0;
-static int wd2_timeout = 0;
-
-#ifdef MODULE
-module_param   (wd0_timeout, int, 0);
-MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
-module_param   (wd1_timeout, int, 0);
-MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
-module_param   (wd2_timeout, int, 0);
-MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
-
-MODULE_AUTHOR
-       ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-       ("Hardware watchdog driver for Sun Microsystems CP1400/1500");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-       ("watchdog");
-#endif /* ifdef MODULE */
-
-/* Forward declarations of internal methods
- */
-#ifdef WD_DEBUG
-static void wd_dumpregs(void);
-#endif
-static irqreturn_t wd_interrupt(int irq, void *dev_id);
-static void wd_toggleintr(struct wd_timer* pTimer, int enable);
-static void wd_pingtimer(struct wd_timer* pTimer);
-static void wd_starttimer(struct wd_timer* pTimer);
-static void wd_resetbrokentimer(struct wd_timer* pTimer);
-static void wd_stoptimer(struct wd_timer* pTimer);
-static void wd_brokentimer(unsigned long data);
-static int  wd_getstatus(struct wd_timer* pTimer);
-
-/* PLD expects words to be written in LSB format,
- * so we must flip all words prior to writing them to regs
- */
-static inline unsigned short flip_word(unsigned short word)
-{
-       return ((word & 0xff) << 8) | ((word >> 8) & 0xff);
-}
-
-#define wd_writew(val, addr)   (writew(flip_word(val), addr))
-#define wd_readw(addr)                         (flip_word(readw(addr)))
-#define wd_writeb(val, addr)   (writeb(val, addr))
-#define wd_readb(addr)                         (readb(addr))
-
-
-/* CP1400s seem to have broken PLD implementations--
- * the interrupt_mask register cannot be written, so
- * no timer interrupts can be masked within the PLD.
- */
-static inline int wd_isbroken(void)
-{
-       /* we could test this by read/write/read/restore
-        * on the interrupt mask register only if OBP
-        * 'watchdog-enable?' == FALSE, but it seems 
-        * ubiquitous on CP1400s
-        */
-       char val[32];
-       prom_getproperty(prom_root_node, "model", val, sizeof(val));
-       return((!strcmp(val, WD_BADMODEL)) ? 1 : 0);
-}
-               
-/* Retrieve watchdog-enable? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_enable(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-reboot? option from OBP
- * Returns 0 if false, 1 if true
- */
-static inline int wd_opt_reboot(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1);
-}
-
-/* Retrieve watchdog-timeout option from OBP
- * Returns OBP value, or 0 if not located
- */
-static inline int wd_opt_timeout(void)
-{
-       int opt_node;
-       char value[32];
-       char *p = value;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       opt_node = prom_getproperty(opt_node, 
-                                                               "watchdog-timeout", 
-                                                               value, 
-                                                               sizeof(value));
-       if(-1 != opt_node) {
-               /* atoi implementation */
-               for(opt_node = 0; /* nop */; p++) {
-                       if(*p >= '0' && *p <= '9') {
-                               opt_node = (10*opt_node)+(*p-'0');
-                       }
-                       else {
-                               break;
-                       }
-               }
-       }
-       return((-1 == opt_node) ? (0) : (opt_node)); 
-}
-
-static int wd_open(struct inode *inode, struct file *f)
-{
-       lock_kernel();
-       switch(iminor(inode))
-       {
-               case WD0_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD0_ID];
-                       break;
-               case WD1_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD1_ID];
-                       break;
-               case WD2_MINOR:
-                       f->private_data = &wd_dev.watchdog[WD2_ID];
-                       break;
-               default:
-                       unlock_kernel();
-                       return(-ENODEV);
-       }
-
-       /* Register IRQ on first open of device */
-       if(0 == wd_dev.initialized)
-       {       
-               if (request_irq(wd_dev.irq, 
-                                               &wd_interrupt, 
-                                               IRQF_SHARED,
-                                               WD_OBPNAME,
-                                               (void *)wd_dev.regs)) {
-                       printk("%s: Cannot register IRQ %d\n", 
-                               WD_OBPNAME, wd_dev.irq);
-                       unlock_kernel();
-                       return(-EBUSY);
-               }
-               wd_dev.initialized = 1;
-       }
-
-       unlock_kernel();
-       return(nonseekable_open(inode, f));
-}
-
-static int wd_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int wd_ioctl(struct inode *inode, struct file *file, 
-                    unsigned int cmd, unsigned long arg)
-{
-       int     setopt                          = 0;
-       struct  wd_timer* pTimer        = (struct wd_timer*)file->private_data;
-       void __user *argp = (void __user *)arg;
-       struct  watchdog_info info      = {
-               0,
-               0,
-               "Altera EPF8820ATC144-4"
-       };
-
-       if(NULL == pTimer) {
-               return(-EINVAL);
-       }
-
-       switch(cmd)
-       {
-               /* Generic Linux IOCTLs */
-               case WDIOC_GETSUPPORT:
-                       if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) {
-                               return(-EFAULT);
-                       }
-                       break;
-               case WDIOC_GETSTATUS:
-               case WDIOC_GETBOOTSTATUS:
-                       if (put_user(0, (int __user *)argp))
-                               return -EFAULT;
-                       break;
-               case WDIOC_KEEPALIVE:
-                       wd_pingtimer(pTimer);
-                       break;
-               case WDIOC_SETOPTIONS:
-                       if(copy_from_user(&setopt, argp, sizeof(unsigned int))) {
-                               return -EFAULT;
-                       }
-                       if(setopt & WDIOS_DISABLECARD) {
-                               if(wd_dev.opt_enable) {
-                                       printk(
-                                               "%s: cannot disable watchdog in ENABLED mode\n",
-                                               WD_OBPNAME);
-                                       return(-EINVAL);
-                               }
-                               wd_stoptimer(pTimer);
-                       }
-                       else if(setopt & WDIOS_ENABLECARD) {
-                               wd_starttimer(pTimer);
-                       }
-                       else {
-                               return(-EINVAL);
-                       }       
-                       break;
-               /* Solaris-compatible IOCTLs */
-               case WIOCGSTAT:
-                       setopt = wd_getstatus(pTimer);
-                       if(copy_to_user(argp, &setopt, sizeof(unsigned int))) {
-                               return(-EFAULT);
-                       }
-                       break;
-               case WIOCSTART:
-                       wd_starttimer(pTimer);
-                       break;
-               case WIOCSTOP:
-                       if(wd_dev.opt_enable) {
-                               printk("%s: cannot disable watchdog in ENABLED mode\n",
-                                       WD_OBPNAME);
-                               return(-EINVAL);
-                       }
-                       wd_stoptimer(pTimer);
-                       break;
-               default:
-                       return(-EINVAL);
-       }
-       return(0);
-}
-
-static long wd_compat_ioctl(struct file *file, unsigned int cmd,
-               unsigned long arg)
-{
-       int rval = -ENOIOCTLCMD;
-
-       switch (cmd) {
-       /* solaris ioctls are specific to this driver */
-       case WIOCSTART:
-       case WIOCSTOP:
-       case WIOCGSTAT:
-               lock_kernel();
-               rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
-               unlock_kernel();
-               break;
-       /* everything else is handled by the generic compat layer */
-       default:
-               break;
-       }
-
-       return rval;
-}
-
-static ssize_t wd_write(struct file    *file, 
-                       const char      __user *buf, 
-                       size_t          count, 
-                       loff_t          *ppos)
-{
-       struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
-
-       if(NULL == pTimer) {
-               return(-EINVAL);
-       }
-
-       if (count) {
-               wd_pingtimer(pTimer);
-               return 1;
-       }
-       return 0;
-}
-
-static ssize_t wd_read(struct file * file, char __user *buffer,
-                       size_t count, loff_t *ppos)
-{
-#ifdef WD_DEBUG
-       wd_dumpregs();
-       return(0);
-#else
-       return(-EINVAL);
-#endif /* ifdef WD_DEBUG */
-}
-
-static irqreturn_t wd_interrupt(int irq, void *dev_id)
-{
-       /* Only WD0 will interrupt-- others are NMI and we won't
-        * see them here....
-        */
-       spin_lock_irq(&wd_dev.lock);
-       if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
-       {
-               wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
-               wd_dev.watchdog[WD0_ID].runstatus |=  WD_STAT_SVCD;
-       }
-       spin_unlock_irq(&wd_dev.lock);
-       return IRQ_HANDLED;
-}
-
-static const struct file_operations wd_fops = {
-       .owner =        THIS_MODULE,
-       .ioctl =        wd_ioctl,
-       .compat_ioctl = wd_compat_ioctl,
-       .open =         wd_open,
-       .write =        wd_write,
-       .read =         wd_read,
-       .release =      wd_release,
-};
-
-static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
-static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
-static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
-
-#ifdef WD_DEBUG
-static void wd_dumpregs(void)
-{
-       /* Reading from downcounters initiates watchdog countdown--
-        * Example is included below for illustration purposes.
-        */
-       int i;
-       printk("%s: dumping register values\n", WD_OBPNAME);
-       for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
-                       /* printk("\t%s%i: dcntr  at 0x%lx: 0x%x\n", 
-                        *      WD_OBPNAME,
-                        *      i,
-                        *      (unsigned long)(&wd_dev.watchdog[i].regs->dcntr), 
-                        *      readw(&wd_dev.watchdog[i].regs->dcntr));
-                        */
-                       printk("\t%s%i: limit  at 0x%lx: 0x%x\n", 
-                               WD_OBPNAME,
-                               i,
-                               (unsigned long)(&wd_dev.watchdog[i].regs->limit), 
-                               readw(&wd_dev.watchdog[i].regs->limit));
-                       printk("\t%s%i: status at 0x%lx: 0x%x\n", 
-                               WD_OBPNAME,
-                               i,
-                               (unsigned long)(&wd_dev.watchdog[i].regs->status), 
-                               readb(&wd_dev.watchdog[i].regs->status));
-                       printk("\t%s%i: driver status: 0x%x\n",
-                               WD_OBPNAME,
-                               i,
-                               wd_getstatus(&wd_dev.watchdog[i]));
-       }
-       printk("\tintr_mask  at %p: 0x%x\n", 
-               wd_dev.regs + PLD_IMASK,
-               readb(wd_dev.regs + PLD_IMASK));
-       printk("\tpld_status at %p: 0x%x\n", 
-               wd_dev.regs + PLD_STATUS, 
-               readb(wd_dev.regs + PLD_STATUS));
-}
-#endif
-
-/* Enable or disable watchdog interrupts
- * Because of the CP1400 defect this should only be
- * called during initialzation or by wd_[start|stop]timer()
- *
- * pTimer      - pointer to timer device, or NULL to indicate all timers 
- * enable      - non-zero to enable interrupts, zero to disable
- */
-static void wd_toggleintr(struct wd_timer* pTimer, int enable)
-{
-       unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK);
-       unsigned char setregs = 
-               (NULL == pTimer) ? 
-                       (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
-                       (pTimer->intr_mask);
-
-       (WD_INTR_ON == enable) ?
-               (curregs &= ~setregs):
-               (curregs |=  setregs);
-
-       wd_writeb(curregs, wd_dev.regs + PLD_IMASK);
-       return;
-}
-
-/* Reset countdown timer with 'limit' value and continue countdown.
- * This will not start a stopped timer.
- *
- * pTimer      - pointer to timer device
- */
-static void wd_pingtimer(struct wd_timer* pTimer)
-{
-       if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-               wd_readw(pTimer->regs + WD_DCNTR);
-       }
-}
-
-/* Stop a running watchdog timer-- the timer actually keeps
- * running, but the interrupt is masked so that no action is
- * taken upon expiration.
- *
- * pTimer      - pointer to timer device
- */
-static void wd_stoptimer(struct wd_timer* pTimer)
-{
-       if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) {
-               wd_toggleintr(pTimer, WD_INTR_OFF);
-
-               if(wd_dev.isbaddoggie) {
-                       pTimer->runstatus |= WD_STAT_BSTOP;
-                       wd_brokentimer((unsigned long)&wd_dev);
-               }
-       }
-}
-
-/* Start a watchdog timer with the specified limit value
- * If the watchdog is running, it will be restarted with
- * the provided limit value.
- *
- * This function will enable interrupts on the specified
- * watchdog.
- *
- * pTimer      - pointer to timer device
- * limit       - limit (countdown) value in 1/10th seconds
- */
-static void wd_starttimer(struct wd_timer* pTimer)
-{
-       if(wd_dev.isbaddoggie) {
-               pTimer->runstatus &= ~WD_STAT_BSTOP;
-       }
-       pTimer->runstatus &= ~WD_STAT_SVCD;
-
-       wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT);
-       wd_toggleintr(pTimer, WD_INTR_ON);
-}
-
-/* Restarts timer with maximum limit value and
- * does not unset 'brokenstop' value.
- */
-static void wd_resetbrokentimer(struct wd_timer* pTimer)
-{
-       wd_toggleintr(pTimer, WD_INTR_ON);
-       wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT);
-}
-
-/* Timer device initialization helper.
- * Returns 0 on success, other on failure
- */
-static int wd_inittimer(int whichdog)
-{
-       struct miscdevice                               *whichmisc;
-       void __iomem *whichregs;
-       char                                                    whichident[8];
-       int                                                             whichmask;
-       __u16                                                   whichlimit;
-
-       switch(whichdog)
-       {
-               case WD0_ID:
-                       whichmisc = &wd0_miscdev;
-                       strcpy(whichident, "RIC");
-                       whichregs = wd_dev.regs + WD0_OFF;
-                       whichmask = WD0_INTR_MASK;
-                       whichlimit= (0 == wd0_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd0_timeout);
-                       break;
-               case WD1_ID:
-                       whichmisc = &wd1_miscdev;
-                       strcpy(whichident, "XIR");
-                       whichregs = wd_dev.regs + WD1_OFF;
-                       whichmask = WD1_INTR_MASK;
-                       whichlimit= (0 == wd1_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd1_timeout);
-                       break;
-               case WD2_ID:
-                       whichmisc = &wd2_miscdev;
-                       strcpy(whichident, "POR");
-                       whichregs = wd_dev.regs + WD2_OFF;
-                       whichmask = WD2_INTR_MASK;
-                       whichlimit= (0 == wd2_timeout)  ? 
-                                               (wd_dev.opt_timeout): 
-                                               (wd2_timeout);
-                       break;
-               default:
-                       printk("%s: %s: invalid watchdog id: %i\n",
-                               WD_OBPNAME, __func__, whichdog);
-                       return(1);
-       }
-       if(0 != misc_register(whichmisc))
-       {
-               return(1);
-       }
-       wd_dev.watchdog[whichdog].regs                  = whichregs;
-       wd_dev.watchdog[whichdog].timeout               = whichlimit;
-       wd_dev.watchdog[whichdog].intr_mask             = whichmask;
-       wd_dev.watchdog[whichdog].runstatus     &= ~WD_STAT_BSTOP;
-       wd_dev.watchdog[whichdog].runstatus     |= WD_STAT_INIT;
-
-       printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", 
-               WD_OBPNAME, 
-               whichdog, 
-               whichident, 
-               wd_dev.watchdog[whichdog].timeout / 10,
-               wd_dev.watchdog[whichdog].timeout % 10,
-               (0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
-       return(0);
-}
-
-/* Timer method called to reset stopped watchdogs--
- * because of the PLD bug on CP1400, we cannot mask
- * interrupts within the PLD so me must continually
- * reset the timers ad infinitum.
- */
-static void wd_brokentimer(unsigned long data)
-{
-       struct wd_device* pDev = (struct wd_device*)data;
-       int id, tripped = 0;
-
-       /* kill a running timer instance, in case we
-        * were called directly instead of by kernel timer
-        */
-       if(timer_pending(&wd_timer)) {
-               del_timer(&wd_timer);
-       }
-
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
-                       ++tripped;
-                       wd_resetbrokentimer(&pDev->watchdog[id]);
-               }
-       }
-
-       if(tripped) {
-               /* there is at least one timer brokenstopped-- reschedule */
-               init_timer(&wd_timer);
-               wd_timer.expires = WD_BTIMEOUT;
-               add_timer(&wd_timer);
-       }
-}
-
-static int wd_getstatus(struct wd_timer* pTimer)
-{
-       unsigned char stat = wd_readb(pTimer->regs + WD_STATUS);
-       unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK);
-       unsigned char ret  = WD_STOPPED;
-
-       /* determine STOPPED */
-       if(0 == stat ) { 
-               return(ret);
-       }
-       /* determine EXPIRED vs FREERUN vs RUNNING */
-       else if(WD_S_EXPIRED & stat) {
-               ret = WD_EXPIRED;
-       }
-       else if(WD_S_RUNNING & stat) {
-               if(intr & pTimer->intr_mask) {
-                       ret = WD_FREERUN;
-               }
-               else {
-                       /* Fudge WD_EXPIRED status for defective CP1400--
-                        * IF timer is running 
-                        *      AND brokenstop is set 
-                        *      AND an interrupt has been serviced
-                        * we are WD_EXPIRED.
-                        *
-                        * IF timer is running 
-                        *      AND brokenstop is set 
-                        *      AND no interrupt has been serviced
-                        * we are WD_FREERUN.
-                        */
-                       if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
-                               if(pTimer->runstatus & WD_STAT_SVCD) {
-                                       ret = WD_EXPIRED;
-                               }
-                               else {
-                                       /* we could as well pretend we are expired */
-                                       ret = WD_FREERUN;
-                               }
-                       }
-                       else {
-                               ret = WD_RUNNING;
-                       }
-               }
-       }
-
-       /* determine SERVICED */
-       if(pTimer->runstatus & WD_STAT_SVCD) {
-               ret |= WD_SERVICED;
-       }
-
-       return(ret);
-}
-
-static int __init wd_init(void)
-{
-       int     id;
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
-                               goto ebus_done;
-               }
-       }
-
-ebus_done:
-       if(!edev) {
-               printk("%s: unable to locate device\n", WD_OBPNAME);
-               return -ENODEV;
-       }
-
-       wd_dev.regs = 
-               ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */
-
-       if(NULL == wd_dev.regs) {
-               printk("%s: unable to map registers\n", WD_OBPNAME);
-               return(-ENODEV);
-       }
-
-       /* initialize device structure from OBP parameters */
-       wd_dev.irq                      = edev->irqs[0];
-       wd_dev.opt_enable       = wd_opt_enable();
-       wd_dev.opt_reboot       = wd_opt_reboot();
-       wd_dev.opt_timeout      = wd_opt_timeout();
-       wd_dev.isbaddoggie      = wd_isbroken();
-
-       /* disable all interrupts unless watchdog-enabled? == true */
-       if(! wd_dev.opt_enable) {
-               wd_toggleintr(NULL, WD_INTR_OFF);
-       }
-
-       /* register miscellaneous devices */
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(0 != wd_inittimer(id)) {
-                       printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
-               }
-       }
-
-       /* warn about possible defective PLD */
-       if(wd_dev.isbaddoggie) {
-               init_timer(&wd_timer);
-               wd_timer.function       = wd_brokentimer;
-               wd_timer.data           = (unsigned long)&wd_dev;
-               wd_timer.expires        = WD_BTIMEOUT;
-
-               printk("%s: PLD defect workaround enabled for model %s\n",
-                       WD_OBPNAME, WD_BADMODEL);
-       }
-       return(0);
-}
-
-static void __exit wd_cleanup(void)
-{
-       int id;
-
-       /* if 'watchdog-enable?' == TRUE, timers are not stopped 
-        * when module is unloaded.  All brokenstopped timers will
-        * also now eventually trip. 
-        */
-       for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
-               if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) {
-                       if(wd_dev.opt_enable) {
-                               printk(KERN_WARNING "%s%i: timer not stopped at release\n",
-                                       WD_OBPNAME, id);
-                       }
-                       else {
-                               wd_stoptimer(&wd_dev.watchdog[id]);
-                               if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
-                                       wd_resetbrokentimer(&wd_dev.watchdog[id]);
-                                       printk(KERN_WARNING 
-                                                       "%s%i: defect workaround disabled at release, "\
-                                                       "timer expires in ~%01i sec\n",
-                                                       WD_OBPNAME, id, 
-                                                       wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10);
-                               }
-                       }
-               }
-       }
-
-       if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
-               del_timer(&wd_timer);
-       }
-       if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd0_miscdev);
-       }
-       if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd1_miscdev);
-       }
-       if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
-               misc_deregister(&wd2_miscdev);
-       }
-       if(0 != wd_dev.initialized) {
-               free_irq(wd_dev.irq, (void *)wd_dev.regs);
-       }
-       iounmap(wd_dev.regs);
-}
-
-module_init(wd_init);
-module_exit(wd_cleanup);
index d8f5c0ca236d7f21b14a21a9b73e1b4483d3984b..2550af4ae432a6bb6cd82c1fbf2c6eccbecb1e99 100644 (file)
@@ -1,10 +1,7 @@
-/* $Id: display7seg.c,v 1.6 2002/01/08 16:00:16 davem Exp $
- *
- * display7seg - Driver implementation for the 7-segment display
- * present on Sun Microsystems CP1400 and CP1500
+/* display7seg.c - Driver implementation for the 7-segment display
+ *                 present on Sun Microsystems CP1400 and CP1500
  *
  * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
- *
  */
 
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/ioport.h>              /* request_region */
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
-#include <asm/ebus.h>                  /* EBus device                                  */
-#include <asm/oplib.h>                 /* OpenProm Library                     */
 #include <asm/uaccess.h>               /* put_/get_user                        */
 #include <asm/io.h>
 
 #include <asm/display7seg.h>
 
 #define D7S_MINOR      193
-#define D7S_OBPNAME    "display7seg"
-#define D7S_DEVNAME "d7s"
+#define DRIVER_NAME    "d7s"
+#define PFX            DRIVER_NAME ": "
 
 static int sol_compat = 0;             /* Solaris compatibility mode   */
 
-#ifdef MODULE
-
 /* Solaris compatibility flag -
  * The Solaris implementation omits support for several
  * documented driver features (ref Sun doc 806-0180-03).  
@@ -46,20 +41,20 @@ static int sol_compat = 0;          /* Solaris compatibility mode   */
  * If you wish the device to operate as under Solaris,
  * omitting above features, set this parameter to non-zero.
  */
-module_param
-       (sol_compat, int, 0);
-MODULE_PARM_DESC
-       (sol_compat, 
-        "Disables documented functionality omitted from Solaris driver");
-
-MODULE_AUTHOR
-       ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
-       ("7-Segment Display driver for Sun Microsystems CP1400/1500");
+module_param(sol_compat, int, 0);
+MODULE_PARM_DESC(sol_compat, 
+                "Disables documented functionality omitted from Solaris driver");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("7-Segment Display driver for Sun Microsystems CP1400/1500");
 MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE
-       ("d7s");
-#endif /* ifdef MODULE */
+MODULE_SUPPORTED_DEVICE("d7s");
+
+struct d7s {
+       void __iomem    *regs;
+       bool            flipped;
+};
+struct d7s *d7s_device;
 
 /*
  * Register block address- see header for details
@@ -72,22 +67,6 @@ MODULE_SUPPORTED_DEVICE
  * FLIP                - Inverts display for upside-down mounted board
  * bits 0-4    - 7-segment display contents
  */
-static void __iomem* d7s_regs;
-
-static inline void d7s_free(void)
-{
-       iounmap(d7s_regs);
-}
-
-static inline int d7s_obpflipped(void)
-{
-       int opt_node;
-
-       opt_node = prom_getchild(prom_root_node);
-       opt_node = prom_searchsiblings(opt_node, "options");
-       return ((-1 != prom_getintdefault(opt_node, "d7s-flipped?", -1)) ? 0 : 1);
-}
-
 static atomic_t d7s_users = ATOMIC_INIT(0);
 
 static int d7s_open(struct inode *inode, struct file *f)
@@ -106,12 +85,15 @@ static int d7s_release(struct inode *inode, struct file *f)
         * are not operating in solaris-compat mode
         */
        if (atomic_dec_and_test(&d7s_users) && !sol_compat) {
-               int regval = 0;
-
-               regval = readb(d7s_regs);
-               (0 == d7s_obpflipped()) ? 
-                       writeb(regval |= D7S_FLIP,  d7s_regs): 
-                       writeb(regval &= ~D7S_FLIP, d7s_regs);
+               struct d7s *p = d7s_device;
+               u8 regval = 0;
+
+               regval = readb(p->regs);
+               if (p->flipped)
+                       regval |= D7S_FLIP;
+               else
+                       regval &= ~D7S_FLIP;
+               writeb(regval, p->regs);
        }
 
        return 0;
@@ -119,9 +101,10 @@ static int d7s_release(struct inode *inode, struct file *f)
 
 static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
-       __u8 regs = readb(d7s_regs);
-       __u8 ireg = 0;
+       struct d7s *p = d7s_device;
+       u8 regs = readb(p->regs);
        int error = 0;
+       u8 ireg = 0;
 
        if (D7S_MINOR != iminor(file->f_path.dentry->d_inode))
                return -ENODEV;
@@ -129,18 +112,20 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        lock_kernel();
        switch (cmd) {
        case D7SIOCWR:
-               /* assign device register values
-                * we mask-out D7S_FLIP if in sol_compat mode
+               /* assign device register values we mask-out D7S_FLIP
+                * if in sol_compat mode
                 */
                if (get_user(ireg, (int __user *) arg)) {
                        error = -EFAULT;
                        break;
                }
-               if (0 != sol_compat) {
-                       (regs & D7S_FLIP) ? 
-                               (ireg |= D7S_FLIP) : (ireg &= ~D7S_FLIP);
+               if (sol_compat) {
+                       if (regs & D7S_FLIP)
+                               ireg |= D7S_FLIP;
+                       else
+                               ireg &= ~D7S_FLIP;
                }
-               writeb(ireg, d7s_regs);
+               writeb(ireg, p->regs);
                break;
 
        case D7SIOCRD:
@@ -158,9 +143,11 @@ static long d7s_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
        case D7SIOCTM:
                /* toggle device mode-- flip display orientation */
-               (regs & D7S_FLIP) ? 
-                       (regs &= ~D7S_FLIP) : (regs |= D7S_FLIP);
-               writeb(regs, d7s_regs);
+               if (regs & D7S_FLIP)
+                       regs &= ~D7S_FLIP;
+               else
+                       regs |= D7S_FLIP;
+               writeb(regs, p->regs);
                break;
        };
        unlock_kernel();
@@ -176,69 +163,123 @@ static const struct file_operations d7s_fops = {
        .release =              d7s_release,
 };
 
-static struct miscdevice d7s_miscdev = { D7S_MINOR, D7S_DEVNAME, &d7s_fops };
+static struct miscdevice d7s_miscdev = {
+       .minor          = D7S_MINOR,
+       .name           = DRIVER_NAME,
+       .fops           = &d7s_fops
+};
 
-static int __init d7s_init(void)
+static int __devinit d7s_probe(struct of_device *op,
+                              const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-       int iTmp = 0, regs = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
-                               goto ebus_done;
-               }
+       struct device_node *opts;
+       int err = -EINVAL;
+       struct d7s *p;
+       u8 regs;
+
+       if (d7s_device)
+               goto out;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!p)
+               goto out;
+
+       p->regs = of_ioremap(&op->resource[0], 0, sizeof(u8), "d7s");
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map chip registers\n");
+               goto out_free;
        }
 
-ebus_done:
-       if(!edev) {
-               printk("%s: unable to locate device\n", D7S_DEVNAME);
-               return -ENODEV;
+       err = misc_register(&d7s_miscdev);
+       if (err) {
+               printk(KERN_ERR PFX "Unable to acquire miscdevice minor %i\n",
+                      D7S_MINOR);
+               goto out_iounmap;
        }
 
-       d7s_regs = ioremap(edev->resource[0].start, sizeof(__u8));
-
-       iTmp = misc_register(&d7s_miscdev);
-       if (0 != iTmp) {
-               printk("%s: unable to acquire miscdevice minor %i\n",
-                      D7S_DEVNAME, D7S_MINOR);
-               iounmap(d7s_regs);
-               return iTmp;
-       }
-
-       /* OBP option "d7s-flipped?" is honored as default
-        * for the device, and reset default when detached
+       /* OBP option "d7s-flipped?" is honored as default for the
+        * device, and reset default when detached
         */
-       regs = readb(d7s_regs);
-       iTmp = d7s_obpflipped();
-       (0 == iTmp) ? 
-               writeb(regs |= D7S_FLIP,  d7s_regs): 
-               writeb(regs &= ~D7S_FLIP, d7s_regs);
-
-       printk("%s: 7-Segment Display%s at 0x%lx %s\n", 
-              D7S_DEVNAME,
-              (0 == iTmp) ? (" (FLIPPED)") : (""),
-              edev->resource[0].start,
-              (0 != sol_compat) ? ("in sol_compat mode") : (""));
-
-       return 0;
+       regs = readb(p->regs);
+       opts = of_find_node_by_path("/options");
+       if (opts &&
+           of_get_property(opts, "d7s-flipped?", NULL))
+               p->flipped = true;
+
+       if (p->flipped)
+               regs |= D7S_FLIP;
+       else
+               regs &= ~D7S_FLIP;
+
+       writeb(regs,  p->regs);
+
+       printk(KERN_INFO PFX "7-Segment Display%s at [%s:0x%lx] %s\n", 
+              op->node->full_name,
+              (regs & D7S_FLIP) ? " (FLIPPED)" : "",
+              op->resource[0].start,
+              sol_compat ? "in sol_compat mode" : "");
+
+       dev_set_drvdata(&op->dev, p);
+       d7s_device = p;
+       err = 0;
+
+out:
+       return err;
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+
+out_free:
+       kfree(p);
+       goto out;
 }
 
-static void __exit d7s_cleanup(void)
+static int __devexit d7s_remove(struct of_device *op)
 {
-       int regs = readb(d7s_regs);
+       struct d7s *p = dev_get_drvdata(&op->dev);
+       u8 regs = readb(p->regs);
 
        /* Honor OBP d7s-flipped? unless operating in solaris-compat mode */
-       if (0 == sol_compat) {
-               (0 == d7s_obpflipped()) ? 
-                       writeb(regs |= D7S_FLIP,  d7s_regs):
-                       writeb(regs &= ~D7S_FLIP, d7s_regs);
+       if (sol_compat) {
+               if (p->flipped)
+                       regs |= D7S_FLIP;
+               else
+                       regs &= ~D7S_FLIP;
+               writeb(regs, p->regs);
        }
 
        misc_deregister(&d7s_miscdev);
-       d7s_free();
+       of_iounmap(&op->resource[0], p->regs, sizeof(u8));
+       kfree(p);
+
+       return 0;
+}
+
+static const struct of_device_id d7s_match[] = {
+       {
+               .name = "display7seg",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, d7s_match);
+
+static struct of_platform_driver d7s_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = d7s_match,
+       .probe          = d7s_probe,
+       .remove         = __devexit_p(d7s_remove),
+};
+
+static int __init d7s_init(void)
+{
+       return of_register_driver(&d7s_driver, &of_bus_type);
+}
+
+static void __exit d7s_exit(void)
+{
+       of_unregister_driver(&d7s_driver);
 }
 
 module_init(d7s_init);
-module_exit(d7s_cleanup);
+module_exit(d7s_exit);
index a408402426f853bf78a21406c975fbf484c0ca8a..58e583b61e60cbc809145041df5eb553dec5db13 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: envctrl.c,v 1.25 2002/01/15 09:01:26 davem Exp $
- * envctrl.c: Temperature and Fan monitoring on Machines providing it.
+/* envctrl.c: Temperature and Fan monitoring on Machines providing it.
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
  * Copyright (C) 2000  Vinh Truong    (vinh.truong@eng.sun.com)
 #include <linux/kmod.h>
 #include <linux/reboot.h>
 #include <linux/smp_lock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
-#include <asm/ebus.h>
 #include <asm/uaccess.h>
 #include <asm/envctrl.h>
 #include <asm/io.h>
 
+#define DRIVER_NAME    "envctrl"
+#define PFX            DRIVER_NAME ": "
+
 #define ENVCTRL_MINOR  162
 
 #define PCF8584_ADDRESS        0x55
@@ -193,7 +196,7 @@ static void envtrl_i2c_test_pin(void)
        } 
 
        if (limit <= 0)
-               printk(KERN_INFO "envctrl: Pin status will not clear.\n");
+               printk(KERN_INFO PFX "Pin status will not clear.\n");
 }
 
 /* Function Description: Test busy bit.
@@ -211,7 +214,7 @@ static void envctrl_i2c_test_bb(void)
        } 
 
        if (limit <= 0)
-               printk(KERN_INFO "envctrl: Busy bit will not clear.\n");
+               printk(KERN_INFO PFX "Busy bit will not clear.\n");
 }
 
 /* Function Description: Send the address for a read access.
@@ -858,11 +861,10 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
 /* Function Description: Initialize i2c child device.
  * Return: None.
  */
-static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
+static void envctrl_init_i2c_child(struct device_node *dp,
                                   struct i2c_child_t *pchild)
 {
        int len, i, tbls_size = 0;
-       struct device_node *dp = edev_child->prom_node;
        const void *pval;
 
        /* Get device address. */
@@ -882,12 +884,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
 
                 pchild->tables = kmalloc(tbls_size, GFP_KERNEL);
                if (pchild->tables == NULL){
-                       printk("envctrl: Failed to allocate table.\n");
+                       printk(KERN_ERR PFX "Failed to allocate table.\n");
                        return;
                }
                pval = of_get_property(dp, "tables", &len);
                 if (!pval || len <= 0) {
-                       printk("envctrl: Failed to get table.\n");
+                       printk(KERN_ERR PFX "Failed to get table.\n");
                        return;
                }
                memcpy(pchild->tables, pval, len);
@@ -993,14 +995,14 @@ static int kenvctrld(void *__unused)
        struct i2c_child_t *cputemp;
 
        if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {
-               printk(KERN_ERR 
-                      "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");
+               printk(KERN_ERR  PFX
+                      "kenvctrld unable to monitor CPU temp-- exiting\n");
                return -ENODEV;
        }
 
        poll_interval = 5000; /* TODO env_mon_interval */
 
-       printk(KERN_INFO "envctrl: %s starting...\n", current->comm);
+       printk(KERN_INFO PFX "%s starting...\n", current->comm);
        for (;;) {
                msleep_interruptible(poll_interval);
 
@@ -1022,54 +1024,35 @@ static int kenvctrld(void *__unused)
                        }
                }
        }
-       printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);
+       printk(KERN_INFO PFX "%s exiting...\n", current->comm);
        return 0;
 }
 
-static int __init envctrl_init(void)
+static int __devinit envctrl_probe(struct of_device *op,
+                                  const struct of_device_id *match)
 {
-       struct linux_ebus *ebus = NULL;
-       struct linux_ebus_device *edev = NULL;
-       struct linux_ebus_child *edev_child = NULL;
-       int err, i = 0;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "bbc")) {
-                               /* If we find a boot-bus controller node,
-                                * then this envctrl driver is not for us.
-                                */
-                               return -ENODEV;
-                       }
-               }
-       }
+       struct device_node *dp;
+       int index, err;
 
-       /* Traverse through ebus and ebus device list for i2c device and
-        * adc and gpio nodes.
-        */
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->prom_node->name, "i2c")) {
-                               i2c = ioremap(edev->resource[0].start, 0x2);
-                               for_each_edevchild(edev, edev_child) {
-                                       if (!strcmp("gpio", edev_child->prom_node->name)) {
-                                               i2c_childlist[i].i2ctype = I2C_GPIO;
-                                               envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-                                       }
-                                       if (!strcmp("adc", edev_child->prom_node->name)) {
-                                               i2c_childlist[i].i2ctype = I2C_ADC;
-                                               envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
-                                       }
-                               }
-                               goto done;
-                       }
+       if (i2c)
+               return -EINVAL;
+
+       i2c = of_ioremap(&op->resource[0], 0, 0x2, DRIVER_NAME);
+       if (!i2c)
+               return -ENOMEM;
+
+       index = 0;
+       dp = op->node->child;
+       while (dp) {
+               if (!strcmp(dp->name, "gpio")) {
+                       i2c_childlist[index].i2ctype = I2C_GPIO;
+                       envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
+               } else if (!strcmp(dp->name, "adc")) {
+                       i2c_childlist[index].i2ctype = I2C_ADC;
+                       envctrl_init_i2c_child(dp, &(i2c_childlist[index++]));
                }
-       }
 
-done:
-       if (!edev) {
-               printk("envctrl: I2C device not found.\n");
-               return -ENODEV;
+               dp = dp->sibling;
        }
 
        /* Set device address. */
@@ -1087,7 +1070,7 @@ done:
        /* Register the device as a minor miscellaneous device. */
        err = misc_register(&envctrl_dev);
        if (err) {
-               printk("envctrl: Unable to get misc minor %d\n",
+               printk(KERN_ERR PFX "Unable to get misc minor %d\n",
                       envctrl_dev.minor);
                goto out_iounmap;
        }
@@ -1096,12 +1079,12 @@ done:
         * a next child device, so we decrement before reverse-traversal of
         * child devices.
         */
-       printk("envctrl: initialized ");
-       for (--i; i >= 0; --i) {
+       printk(KERN_INFO PFX "Initialized ");
+       for (--index; index >= 0; --index) {
                printk("[%s 0x%lx]%s", 
-                       (I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 
-                       ((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 
-                       i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));
+                       (I2C_ADC == i2c_childlist[index].i2ctype) ? "adc" : 
+                       ((I2C_GPIO == i2c_childlist[index].i2ctype) ? "gpio" : "unknown"), 
+                       i2c_childlist[index].addr, (0 == index) ? "\n" : " ");
        }
 
        kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");
@@ -1115,26 +1098,54 @@ done:
 out_deregister:
        misc_deregister(&envctrl_dev);
 out_iounmap:
-       iounmap(i2c);
-       for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-               kfree(i2c_childlist[i].tables);
+       of_iounmap(&op->resource[0], i2c, 0x2);
+       for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+               kfree(i2c_childlist[index].tables);
 
        return err;
 }
 
-static void __exit envctrl_cleanup(void)
+static int __devexit envctrl_remove(struct of_device *op)
 {
-       int i;
+       int index;
 
        kthread_stop(kenvctrld_task);
 
-       iounmap(i2c);
+       of_iounmap(&op->resource[0], i2c, 0x2);
        misc_deregister(&envctrl_dev);
 
-       for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)
-               kfree(i2c_childlist[i].tables);
+       for (index = 0; index < ENVCTRL_MAX_CPU * 2; index++)
+               kfree(i2c_childlist[index].tables);
+
+       return 0;
+}
+
+static const struct of_device_id envctrl_match[] = {
+       {
+               .name = "i2c",
+               .compatible = "i2cpcf,8584",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, envctrl_match);
+
+static struct of_platform_driver envctrl_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = envctrl_match,
+       .probe          = envctrl_probe,
+       .remove         = __devexit_p(envctrl_remove),
+};
+
+static int __init envctrl_init(void)
+{
+       return of_register_driver(&envctrl_driver, &of_bus_type);
+}
+
+static void __exit envctrl_exit(void)
+{
+       of_unregister_driver(&envctrl_driver);
 }
 
 module_init(envctrl_init);
-module_exit(envctrl_cleanup);
+module_exit(envctrl_exit);
 MODULE_LICENSE("GPL");
index 7d95e151513a0a5446e07ef6da24d9605334af53..41083472ff4f46298ce3c8f97484d38df6acb788 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id: flash.c,v 1.25 2001/12/21 04:56:16 davem Exp $
- * flash.c: Allow mmap access to the OBP Flash, for OBP updates.
+/* flash.c: Allow mmap access to the OBP Flash, for OBP updates.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
  */
 #include <linux/smp_lock.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/ebus.h>
 #include <asm/upa.h>
 
 static DEFINE_SPINLOCK(flash_lock);
@@ -161,97 +160,68 @@ static const struct file_operations flash_fops = {
 
 static struct miscdevice flash_dev = { FLASH_MINOR, "flash", &flash_fops };
 
-static int __init flash_init(void)
+static int __devinit flash_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev = NULL;
-#ifdef CONFIG_PCI
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev = NULL;
-       struct linux_prom_registers regs[2];
-       int len, nregs;
-#endif
-       int err;
-
-       for_all_sbusdev(sdev, sbus) {
-               if (!strcmp(sdev->prom_name, "flashprom")) {
-                       if (sdev->reg_addrs[0].phys_addr == sdev->reg_addrs[1].phys_addr) {
-                               flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-                               flash.read_size = sdev->reg_addrs[0].reg_size;
-                               flash.write_base = flash.read_base;
-                               flash.write_size = flash.read_size;
-                       } else {
-                               flash.read_base = ((unsigned long)sdev->reg_addrs[0].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[0].which_io)<<32UL);
-                               flash.read_size = sdev->reg_addrs[0].reg_size;
-                               flash.write_base = ((unsigned long)sdev->reg_addrs[1].phys_addr) |
-                                       (((unsigned long)sdev->reg_addrs[1].which_io)<<32UL);
-                               flash.write_size = sdev->reg_addrs[1].reg_size;
-                       }
-                       flash.busy = 0;
-                       break;
-               }
-       }
-       if (!sdev) {
-#ifdef CONFIG_PCI
-               const struct linux_prom_registers *ebus_regs;
-
-               for_each_ebus(ebus) {
-                       for_each_ebusdev(edev, ebus) {
-                               if (!strcmp(edev->prom_node->name, "flashprom"))
-                                       goto ebus_done;
-                       }
-               }
-       ebus_done:
-               if (!edev)
-                       return -ENODEV;
-
-               ebus_regs = of_get_property(edev->prom_node, "reg", &len);
-               if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
-                       printk("flash: Strange reg property size %d\n", len);
-                       return -ENODEV;
-               }
-
-               nregs = len / sizeof(ebus_regs[0]);
+       struct device_node *dp = op->node;
+       struct device_node *parent;
 
-               flash.read_base = edev->resource[0].start;
-               flash.read_size = ebus_regs[0].reg_size;
+       parent = dp->parent;
 
-               if (nregs == 1) {
-                       flash.write_base = edev->resource[0].start;
-                       flash.write_size = ebus_regs[0].reg_size;
-               } else if (nregs == 2) {
-                       flash.write_base = edev->resource[1].start;
-                       flash.write_size = ebus_regs[1].reg_size;
-               } else {
-                       printk("flash: Strange number of regs %d\n", nregs);
-                       return -ENODEV;
-               }
-
-               flash.busy = 0;
-
-#else
+       if (strcmp(parent->name, "sbus") &&
+           strcmp(parent->name, "sbi") &&
+           strcmp(parent->name, "ebus"))
                return -ENODEV;
-#endif
+
+       flash.read_base = op->resource[0].start;
+       flash.read_size = resource_size(&op->resource[0]);
+       if (op->resource[1].flags) {
+               flash.write_base = op->resource[1].start;
+               flash.write_size = resource_size(&op->resource[1]);
+       } else {
+               flash.write_base = op->resource[0].start;
+               flash.write_size = resource_size(&op->resource[0]);
        }
+       flash.busy = 0;
 
-       printk("OBP Flash: RD %lx[%lx] WR %lx[%lx]\n",
+       printk(KERN_INFO "%s: OBP Flash, RD %lx[%lx] WR %lx[%lx]\n",
+              op->node->full_name,
               flash.read_base, flash.read_size,
               flash.write_base, flash.write_size);
 
-       err = misc_register(&flash_dev);
-       if (err) {
-               printk(KERN_ERR "flash: unable to get misc minor\n");
-               return err;
-       }
+       return misc_register(&flash_dev);
+}
+
+static int __devexit flash_remove(struct of_device *op)
+{
+       misc_deregister(&flash_dev);
 
        return 0;
 }
 
+static const struct of_device_id flash_match[] = {
+       {
+               .name = "flashprom",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, flash_match);
+
+static struct of_platform_driver flash_driver = {
+       .name           = "flash",
+       .match_table    = flash_match,
+       .probe          = flash_probe,
+       .remove         = __devexit_p(flash_remove),
+};
+
+static int __init flash_init(void)
+{
+       return of_register_driver(&flash_driver, &of_bus_type);
+}
+
 static void __exit flash_cleanup(void)
 {
-       misc_deregister(&flash_dev);
+       of_unregister_driver(&flash_driver);
 }
 
 module_init(flash_init);
diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c
deleted file mode 100644 (file)
index b042991..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/* $Id: rtc.c,v 1.28 2001/10/08 22:19:51 davem Exp $
- *
- * 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 SPARC Mostek real time clock chip. It is no use unless you
- * use the modified clock utility.
- *
- * Get the modified clock utility from:
- *   ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c
- */
-
-#include <linux/module.h>
-#include <linux/smp_lock.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/mostek.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/rtc.h>
-
-static int rtc_busy = 0;
-
-/* This is the structure layout used by drivers/char/rtc.c, we
- * support that driver's ioctls so that things are less messy in
- * userspace.
- */
-struct rtc_time_generic {
-       int tm_sec;
-       int tm_min;
-       int tm_hour;
-       int tm_mday;
-       int tm_mon;
-       int tm_year;
-       int tm_wday;
-       int tm_yday;
-       int tm_isdst;
-};
-#define RTC_AIE_ON     _IO('p', 0x01)  /* Alarm int. enable on         */
-#define RTC_AIE_OFF    _IO('p', 0x02)  /* ... off                      */
-#define RTC_UIE_ON     _IO('p', 0x03)  /* Update int. enable on        */
-#define RTC_UIE_OFF    _IO('p', 0x04)  /* ... off                      */
-#define RTC_PIE_ON     _IO('p', 0x05)  /* Periodic int. enable on      */
-#define RTC_PIE_OFF    _IO('p', 0x06)  /* ... off                      */
-#define RTC_WIE_ON     _IO('p', 0x0f)  /* Watchdog int. enable on      */
-#define RTC_WIE_OFF    _IO('p', 0x10)  /* ... off                      */
-#define RTC_RD_TIME    _IOR('p', 0x09, struct rtc_time_generic) /* Read RTC time   */
-#define RTC_SET_TIME   _IOW('p', 0x0a, struct rtc_time_generic) /* Set RTC time    */
-#define RTC_ALM_SET    _IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
-#define RTC_ALM_READ   _IOR('p', 0x08, struct rtc_time) /* Read alarm time */
-#define RTC_IRQP_READ  _IOR('p', 0x0b, unsigned long)   /* Read IRQ rate   */
-#define RTC_IRQP_SET   _IOW('p', 0x0c, unsigned long)   /* Set IRQ rate    */
-#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long)   /* Read epoch      */
-#define RTC_EPOCH_SET  _IOW('p', 0x0e, unsigned long)   /* Set epoch       */
-#define RTC_WKALM_SET  _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/
-#define RTC_WKALM_RD   _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/
-#define RTC_PLL_GET    _IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
-#define RTC_PLL_SET    _IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
-
-/* Retrieve the current date and time from the real time clock. */
-static void get_rtc_time(struct rtc_time *t)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       t->sec = MSTK_REG_SEC(regs);
-       t->min = MSTK_REG_MIN(regs);
-       t->hour = MSTK_REG_HOUR(regs);
-       t->dow = MSTK_REG_DOW(regs);
-       t->dom = MSTK_REG_DOM(regs);
-       t->month = MSTK_REG_MONTH(regs);
-       t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_READ;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-}
-
-/* Set the current date and time inthe real time clock. */
-void set_rtc_time(struct rtc_time *t)
-{
-       void __iomem *regs = mstk48t02_regs;
-       u8 tmp;
-
-       spin_lock_irq(&mostek_lock);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp |= MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       MSTK_SET_REG_SEC(regs,t->sec);
-       MSTK_SET_REG_MIN(regs,t->min);
-       MSTK_SET_REG_HOUR(regs,t->hour);
-       MSTK_SET_REG_DOW(regs,t->dow);
-       MSTK_SET_REG_DOM(regs,t->dom);
-       MSTK_SET_REG_MONTH(regs,t->month);
-       MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO);
-
-       tmp = mostek_read(regs + MOSTEK_CREG);
-       tmp &= ~MSTK_CREG_WRITE;
-       mostek_write(regs + MOSTEK_CREG, tmp);
-
-       spin_unlock_irq(&mostek_lock);
-}
-
-static int put_rtc_time_generic(void __user *argp, struct rtc_time *tm)
-{
-       struct rtc_time_generic __user *utm = argp;
-
-       if (__put_user(tm->sec, &utm->tm_sec) ||
-           __put_user(tm->min, &utm->tm_min) ||
-           __put_user(tm->hour, &utm->tm_hour) ||
-           __put_user(tm->dom, &utm->tm_mday) ||
-           __put_user(tm->month, &utm->tm_mon) ||
-           __put_user(tm->year, &utm->tm_year) ||
-           __put_user(tm->dow, &utm->tm_wday) ||
-           __put_user(0, &utm->tm_yday) ||
-           __put_user(0, &utm->tm_isdst))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int get_rtc_time_generic(struct rtc_time *tm, void __user *argp)
-{
-       struct rtc_time_generic __user *utm = argp;
-
-       if (__get_user(tm->sec, &utm->tm_sec) ||
-           __get_user(tm->min, &utm->tm_min) ||
-           __get_user(tm->hour, &utm->tm_hour) ||
-           __get_user(tm->dom, &utm->tm_mday) ||
-           __get_user(tm->month, &utm->tm_mon) ||
-           __get_user(tm->year, &utm->tm_year) ||
-           __get_user(tm->dow, &utm->tm_wday))
-               return -EFAULT;
-
-       return 0;
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-       unsigned long arg)
-{
-       struct rtc_time rtc_tm;
-       void __user *argp = (void __user *)arg;
-
-       switch (cmd) {
-       /* No interrupt support, return an error
-        * compatible with drivers/char/rtc.c
-        */
-       case RTC_AIE_OFF:
-       case RTC_AIE_ON:
-       case RTC_PIE_OFF:
-       case RTC_PIE_ON:
-       case RTC_UIE_OFF:
-       case RTC_UIE_ON:
-       case RTC_IRQP_READ:
-       case RTC_IRQP_SET:
-       case RTC_EPOCH_SET:
-       case RTC_EPOCH_READ:
-               return -EINVAL;
-
-       case RTCGET:
-       case RTC_RD_TIME:
-               memset(&rtc_tm, 0, sizeof(struct rtc_time));
-               get_rtc_time(&rtc_tm);
-
-               if (cmd == RTCGET) {
-                       if (copy_to_user(argp, &rtc_tm,
-                                        sizeof(struct rtc_time)))
-                               return -EFAULT;
-               } else if (put_rtc_time_generic(argp, &rtc_tm))
-                       return -EFAULT;
-
-               return 0;
-
-
-       case RTCSET:
-       case RTC_SET_TIME:
-               if (!capable(CAP_SYS_TIME))
-                       return -EPERM;
-
-               if (cmd == RTCSET) {
-                       if (copy_from_user(&rtc_tm, argp,
-                                          sizeof(struct rtc_time)))
-                               return -EFAULT;
-               } else if (get_rtc_time_generic(&rtc_tm, argp))
-                       return -EFAULT;
-
-               set_rtc_time(&rtc_tm);
-
-               return 0;
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
-       int ret;
-
-       lock_kernel();
-       spin_lock_irq(&mostek_lock);
-       if (rtc_busy) {
-               ret = -EBUSY;
-       } else {
-               rtc_busy = 1;
-               ret = 0;
-       }
-       spin_unlock_irq(&mostek_lock);
-       unlock_kernel();
-
-       return ret;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
-       rtc_busy = 0;
-
-       return 0;
-}
-
-static const struct file_operations rtc_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .ioctl =        rtc_ioctl,
-       .open =         rtc_open,
-       .release =      rtc_release,
-};
-
-static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
-
-static int __init rtc_sun_init(void)
-{
-       int error;
-
-       /* It is possible we are being driven by some other RTC chip
-        * and thus another RTC driver is handling things.
-        */
-       if (!mstk48t02_regs)
-               return -ENODEV;
-
-       error = misc_register(&rtc_dev);
-       if (error) {
-               printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n");
-               return error;
-       }
-       printk("rtc_sun_init: Registered Mostek RTC driver.\n");
-
-       return 0;
-}
-
-static void __exit rtc_sun_cleanup(void)
-{
-       misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_sun_init);
-module_exit(rtc_sun_cleanup);
-MODULE_LICENSE("GPL");
index 777637594acd3c11eb4c376d2547dd11ff6d5234..27993c37775d863f62b9ff55515753d40dc19d29 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: uctrl.c,v 1.12 2001/10/08 22:19:51 davem Exp $
- * uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
+/* uctrl.c: TS102 Microcontroller interface on Tadpole Sparcbook 3
  *
  * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
+ * Copyright 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/module.h>
@@ -14,6 +14,8 @@
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/openprom.h>
 #include <asm/oplib.h>
@@ -21,7 +23,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
-#include <asm/sbus.h>
 
 #define UCTRL_MINOR    174
 
 #endif
 
 struct uctrl_regs {
-       volatile u32 uctrl_intr;
-       volatile u32 uctrl_data;
-       volatile u32 uctrl_stat;
-       volatile u32 uctrl_xxx[5];
+       u32 uctrl_intr;
+       u32 uctrl_data;
+       u32 uctrl_stat;
+       u32 uctrl_xxx[5];
 };
 
 struct ts102_regs {
-       volatile u32 card_a_intr;
-       volatile u32 card_a_stat;
-       volatile u32 card_a_ctrl;
-       volatile u32 card_a_xxx;
-       volatile u32 card_b_intr;
-       volatile u32 card_b_stat;
-       volatile u32 card_b_ctrl;
-       volatile u32 card_b_xxx;
-       volatile u32 uctrl_intr;
-       volatile u32 uctrl_data;
-       volatile u32 uctrl_stat;
-       volatile u32 uctrl_xxx;
-       volatile u32 ts102_xxx[4];
+       u32 card_a_intr;
+       u32 card_a_stat;
+       u32 card_a_ctrl;
+       u32 card_a_xxx;
+       u32 card_b_intr;
+       u32 card_b_stat;
+       u32 card_b_ctrl;
+       u32 card_b_xxx;
+       u32 uctrl_intr;
+       u32 uctrl_data;
+       u32 uctrl_stat;
+       u32 uctrl_xxx;
+       u32 ts102_xxx[4];
 };
 
 /* Bits for uctrl_intr register */
@@ -186,17 +187,15 @@ enum uctrl_opcode {
   POWER_RESTART=0x83,
 };
 
-struct uctrl_driver {
-       struct uctrl_regs *regs;
+static struct uctrl_driver {
+       struct uctrl_regs __iomem *regs;
        int irq;
        int pending;
        struct uctrl_status status;
-};
-
-static struct uctrl_driver drv;
+} *global_driver;
 
-static void uctrl_get_event_status(void);
-static void uctrl_get_external_status(void);
+static void uctrl_get_event_status(struct uctrl_driver *);
+static void uctrl_get_external_status(struct uctrl_driver *);
 
 static int
 uctrl_ioctl(struct inode *inode, struct file *file,
@@ -213,16 +212,14 @@ static int
 uctrl_open(struct inode *inode, struct file *file)
 {
        lock_kernel();
-       uctrl_get_event_status();
-       uctrl_get_external_status();
+       uctrl_get_event_status(global_driver);
+       uctrl_get_external_status(global_driver);
        unlock_kernel();
        return 0;
 }
 
 static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
 {
-       struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
-       printk("in uctrl_interrupt\n");
        return IRQ_HANDLED;
 }
 
@@ -244,11 +241,11 @@ static struct miscdevice uctrl_dev = {
 { \
   unsigned int i; \
   for (i = 0; i < 10000; i++) { \
-    if (UCTRL_STAT_TXNF_STA & driver->regs->uctrl_stat) \
+      if (UCTRL_STAT_TXNF_STA & sbus_readl(&driver->regs->uctrl_stat)) \
       break; \
   } \
   dprintk(("write data 0x%02x\n", value)); \
-  driver->regs->uctrl_data = value; \
+  sbus_writel(value, &driver->regs->uctrl_data); \
 }
 
 /* Wait for something to read, read it, then clear the bit */
@@ -257,24 +254,23 @@ static struct miscdevice uctrl_dev = {
   unsigned int i; \
   value = 0; \
   for (i = 0; i < 10000; i++) { \
-    if ((UCTRL_STAT_RXNE_STA & driver->regs->uctrl_stat) == 0) \
+      if ((UCTRL_STAT_RXNE_STA & sbus_readl(&driver->regs->uctrl_stat)) == 0) \
       break; \
     udelay(1); \
   } \
-  value = driver->regs->uctrl_data; \
+  value = sbus_readl(&driver->regs->uctrl_data); \
   dprintk(("read data 0x%02x\n", value)); \
-  driver->regs->uctrl_stat = UCTRL_STAT_RXNE_STA; \
+  sbus_writel(UCTRL_STAT_RXNE_STA, &driver->regs->uctrl_stat); \
 }
 
-static void uctrl_do_txn(struct uctrl_txn *txn)
+static void uctrl_do_txn(struct uctrl_driver *driver, struct uctrl_txn *txn)
 {
-       struct uctrl_driver *driver = &drv;
        int stat, incnt, outcnt, bytecnt, intr;
        u32 byte;
 
-       stat = driver->regs->uctrl_stat;
-       intr = driver->regs->uctrl_intr;
-       driver->regs->uctrl_stat = stat;
+       stat = sbus_readl(&driver->regs->uctrl_stat);
+       intr = sbus_readl(&driver->regs->uctrl_intr);
+       sbus_writel(stat, &driver->regs->uctrl_stat);
 
        dprintk(("interrupt stat 0x%x int 0x%x\n", stat, intr));
 
@@ -305,9 +301,8 @@ static void uctrl_do_txn(struct uctrl_txn *txn)
        }
 }
 
-static void uctrl_get_event_status(void)
+static void uctrl_get_event_status(struct uctrl_driver *driver)
 {
-       struct uctrl_driver *driver = &drv;
        struct uctrl_txn txn;
        u8 outbits[2];
 
@@ -317,7 +312,7 @@ static void uctrl_get_event_status(void)
        txn.inbuf = NULL;
        txn.outbuf = outbits;
 
-       uctrl_do_txn(&txn);
+       uctrl_do_txn(driver, &txn);
 
        dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
        driver->status.event_status = 
@@ -325,9 +320,8 @@ static void uctrl_get_event_status(void)
        dprintk(("ev is %x\n", driver->status.event_status));
 }
 
-static void uctrl_get_external_status(void)
+static void uctrl_get_external_status(struct uctrl_driver *driver)
 {
-       struct uctrl_driver *driver = &drv;
        struct uctrl_txn txn;
        u8 outbits[2];
        int i, v;
@@ -338,7 +332,7 @@ static void uctrl_get_external_status(void)
        txn.inbuf = NULL;
        txn.outbuf = outbits;
 
-       uctrl_do_txn(&txn);
+       uctrl_do_txn(driver, &txn);
 
        dprintk(("bytes %x %x\n", (outbits[0] & 0xff), (outbits[1] & 0xff)));
        driver->status.external_status = 
@@ -354,71 +348,101 @@ static void uctrl_get_external_status(void)
        
 }
 
-static int __init ts102_uctrl_init(void)
+static int __devinit uctrl_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct uctrl_driver *driver = &drv;
-       int len;
-       struct linux_prom_irqs tmp_irq[2];
-        unsigned int vaddr[2] = { 0, 0 };
-       int tmpnode, uctrlnode = prom_getchild(prom_root_node);
-       int err;
+       struct uctrl_driver *p;
+       int err = -ENOMEM;
 
-       tmpnode = prom_searchsiblings(uctrlnode, "obio");
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               printk(KERN_ERR "uctrl: Unable to allocate device struct.\n");
+               goto out;
+       }
 
-       if (tmpnode)
-         uctrlnode = prom_getchild(tmpnode);
+       p->regs = of_ioremap(&op->resource[0], 0,
+                            resource_size(&op->resource[0]),
+                            "uctrl");
+       if (!p->regs) {
+               printk(KERN_ERR "uctrl: Unable to map registers.\n");
+               goto out_free;
+       }
 
-       uctrlnode = prom_searchsiblings(uctrlnode, "uctrl");
+       p->irq = op->irqs[0];
+       err = request_irq(p->irq, uctrl_interrupt, 0, "uctrl", p);
+       if (err) {
+               printk(KERN_ERR "uctrl: Unable to register irq.\n");
+               goto out_iounmap;
+       }
 
-       if (!uctrlnode)
-               return -ENODEV;
+       err = misc_register(&uctrl_dev);
+       if (err) {
+               printk(KERN_ERR "uctrl: Unable to register misc device.\n");
+               goto out_free_irq;
+       }
 
-       /* the prom mapped it for us */
-       len = prom_getproperty(uctrlnode, "address", (void *) vaddr,
-                              sizeof(vaddr));
-       driver->regs = (struct uctrl_regs *)vaddr[0];
+       sbus_writel(UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK, &p->regs->uctrl_intr);
+       printk(KERN_INFO "%s: uctrl regs[0x%p] (irq %d)\n",
+              op->node->full_name, p->regs, p->irq);
+       uctrl_get_event_status(p);
+       uctrl_get_external_status(p);
 
-       len = prom_getproperty(uctrlnode, "intr", (char *) tmp_irq,
-                              sizeof(tmp_irq));
+       dev_set_drvdata(&op->dev, p);
+       global_driver = p;
 
-       /* Flush device */
-       READUCTLDATA(len);
+out:
+       return err;
 
-       if(!driver->irq) 
-               driver->irq = tmp_irq[0].pri;
+out_free_irq:
+       free_irq(p->irq, p);
 
-       err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
-       if (err) {
-               printk("%s: unable to register irq %d\n",
-                      __func__, driver->irq);
-               return err;
-       }
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
 
-       if (misc_register(&uctrl_dev)) {
-               printk("%s: unable to get misc minor %d\n",
-                      __func__, uctrl_dev.minor);
-               free_irq(driver->irq, driver);
-               return -ENODEV;
-       }
+out_free:
+       kfree(p);
+       goto out;
+}
 
-       driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
-       printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
-       uctrl_get_event_status();
-       uctrl_get_external_status();
-        return 0;
+static int __devexit uctrl_remove(struct of_device *op)
+{
+       struct uctrl_driver *p = dev_get_drvdata(&op->dev);
+
+       if (p) {
+               misc_deregister(&uctrl_dev);
+               free_irq(p->irq, p);
+               of_iounmap(&op->resource[0], p->regs, resource_size(&op->resource[0]));
+               kfree(p);
+       }
+       return 0;
 }
 
-static void __exit ts102_uctrl_cleanup(void)
+static const struct of_device_id uctrl_match[] = {
+       {
+               .name = "uctrl",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, uctrl_match);
+
+static struct of_platform_driver uctrl_driver = {
+       .name           = "uctrl",
+       .match_table    = uctrl_match,
+       .probe          = uctrl_probe,
+       .remove         = __devexit_p(uctrl_remove),
+};
+
+
+static int __init uctrl_init(void)
 {
-       struct uctrl_driver *driver = &drv;
+       return of_register_driver(&uctrl_driver, &of_bus_type);
+}
 
-       misc_deregister(&uctrl_dev);
-       if (driver->irq)
-               free_irq(driver->irq, driver);
-       if (driver->regs)
-               driver->regs = NULL;
+static void __exit uctrl_exit(void)
+{
+       of_unregister_driver(&uctrl_driver);
 }
 
-module_init(ts102_uctrl_init);
-module_exit(ts102_uctrl_cleanup);
+module_init(uctrl_init);
+module_exit(uctrl_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
deleted file mode 100644 (file)
index a5240c5..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-#ifndef _LINUX_VFC_H_
-#define _LINUX_VFC_H_
-
-/*
- * The control register for the vfc is at offset 0x4000
- * The first field ram bank is located at offset 0x5000
- * The second field ram bank is at offset 0x7000
- * i2c_reg address the Phillips PCF8584(see notes in vfc_i2c.c) 
- *    data and transmit register.
- * i2c_s1 controls register s1 of the PCF8584
- * i2c_write seems to be similar to i2c_write but I am not 
- *    quite sure why sun uses it
- * 
- * I am also not sure whether or not you can read the fram bank as a
- * whole or whether you must read each word individually from offset
- * 0x5000 as soon as I figure it out I will update this file */
-
-struct vfc_regs {
-       char pad1[0x4000];
-       unsigned int control;  /* Offset 0x4000 */
-       char pad2[0xffb];      /* from offset 0x4004 to 0x5000 */
-       unsigned int fram_bank1; /* Offset 0x5000 */
-       char pad3[0xffb];        /* from offset 0x5004 to 0x6000 */
-       unsigned int i2c_reg; /* Offset 0x6000 */
-       unsigned int i2c_magic2; /* Offset 0x6004 */
-       unsigned int i2c_s1;  /* Offset 0x6008 */
-       unsigned int i2c_write; /* Offset 0x600c */
-       char pad4[0xff0];     /* from offset 0x6010 to 0x7000 */
-       unsigned int fram_bank2; /* Offset 0x7000 */
-       char pad5[0x1000];
-};
-
-#define VFC_SAA9051_NR (13)
-#define VFC_SAA9051_ADDR (0x8a)
-       /* The saa9051 returns the following for its status 
-        * bit 0 - 0
-        * bit 1 - SECAM color detected (1=found,0=not found)
-        * bit 2 - COLOR detected (1=found,0=not found)
-        * bit 3 - 0
-        * bit 4 - Field frequency bit (1=60Hz (NTSC), 0=50Hz (PAL))
-        * bit 5 - 1
-        * bit 6 - horizontal frequency lock (1=transmitter found,
-        *                                    0=no transmitter)
-        * bit 7 - Power on reset bit (1=reset,0=at least one successful 
-        *                                       read of the status byte)
-        */
-
-#define VFC_SAA9051_PONRES (0x80)
-#define VFC_SAA9051_HLOCK (0x40)
-#define VFC_SAA9051_FD (0x10)
-#define VFC_SAA9051_CD (0x04)
-#define VFC_SAA9051_CS (0x02)
-
-
-/* The various saa9051 sub addresses */
-
-#define VFC_SAA9051_IDEL (0) 
-#define VFC_SAA9051_HSY_START (1)
-#define VFC_SAA9051_HSY_STOP (2)
-#define VFC_SAA9051_HC_START (3)
-#define VFC_SAA9051_HC_STOP (4)
-#define VFC_SAA9051_HS_START (5)
-#define VFC_SAA9051_HORIZ_PEAK (6)
-#define VFC_SAA9051_HUE (7)
-#define VFC_SAA9051_C1 (8)
-#define VFC_SAA9051_C2 (9)
-#define VFC_SAA9051_C3 (0xa)
-#define VFC_SAA9051_SECAM_DELAY (0xb)
-
-
-/* Bit settings for saa9051 sub address 0x06 */
-
-#define VFC_SAA9051_AP1 (0x01)
-#define VFC_SAA9051_AP2 (0x02)
-#define VFC_SAA9051_COR1 (0x04)
-#define VFC_SAA9051_COR2 (0x08)
-#define VFC_SAA9051_BP1 (0x10)
-#define VFC_SAA9051_BP2 (0x20)
-#define VFC_SAA9051_PF (0x40)
-#define VFC_SAA9051_BY (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x08 */
-
-#define VFC_SAA9051_CCFR0 (0x01)
-#define VFC_SAA9051_CCFR1 (0x02)
-#define VFC_SAA9051_YPN (0x04)
-#define VFC_SAA9051_ALT (0x08)
-#define VFC_SAA9051_CO (0x10)
-#define VFC_SAA9051_VTR (0x20)
-#define VFC_SAA9051_FS (0x40)
-#define VFC_SAA9051_HPLL (0x80)
-
-
-/* Bit settings for saa9051 sub address 9 */
-
-#define VFC_SAA9051_SS0 (0x01)
-#define VFC_SAA9051_SS1 (0x02)
-#define VFC_SAA9051_AFCC (0x04)
-#define VFC_SAA9051_CI (0x08)
-#define VFC_SAA9051_SA9D4 (0x10) /* Don't care bit */
-#define VFC_SAA9051_OEC (0x20)
-#define VFC_SAA9051_OEY (0x40)
-#define VFC_SAA9051_VNL (0x80)
-
-
-/* Bit settings for saa9051 sub address 0x0A */
-
-#define VFC_SAA9051_YDL0 (0x01)
-#define VFC_SAA9051_YDL1 (0x02)
-#define VFC_SAA9051_YDL2 (0x04)
-#define VFC_SAA9051_SS2 (0x08)
-#define VFC_SAA9051_SS3 (0x10)
-#define VFC_SAA9051_YC (0x20)
-#define VFC_SAA9051_CT (0x40)
-#define VFC_SAA9051_SYC (0x80)
-
-
-#define VFC_SAA9051_SA(a,b) ((a)->saa9051_state_array[(b)+1])
-#define vfc_update_saa9051(a) (vfc_i2c_sendbuf((a),VFC_SAA9051_ADDR,\
-                                           (a)->saa9051_state_array,\
-                                           VFC_SAA9051_NR))
-
-
-struct vfc_dev {
-       volatile struct vfc_regs __iomem *regs;
-       struct vfc_regs *phys_regs;
-       unsigned int control_reg;
-       struct mutex device_lock_mtx;
-       int instance;
-       int busy;
-       unsigned long which_io;
-       unsigned char saa9051_state_array[VFC_SAA9051_NR];
-};
-
-void captstat_reset(struct vfc_dev *);
-void memptr_reset(struct vfc_dev *);
-
-int vfc_pcf8584_init(struct vfc_dev *);
-void vfc_i2c_delay_no_busy(struct vfc_dev *, unsigned long);
-void vfc_i2c_delay(struct vfc_dev *);
-int vfc_i2c_sendbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_recvbuf(struct vfc_dev *, unsigned char, char *, int) ;
-int vfc_i2c_reset_bus(struct vfc_dev *);
-int vfc_init_i2c_bus(struct vfc_dev *);
-
-#define VFC_CONTROL_DIAGMODE  0x10000000
-#define VFC_CONTROL_MEMPTR    0x20000000
-#define VFC_CONTROL_CAPTURE   0x02000000
-#define VFC_CONTROL_CAPTRESET 0x04000000
-
-#define VFC_STATUS_CAPTURE    0x08000000
-
-#ifdef VFC_IOCTL_DEBUG
-#define VFC_IOCTL_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_IOCTL_DEBUG_PRINTK(a)
-#endif
-
-#ifdef VFC_I2C_DEBUG
-#define VFC_I2C_DEBUG_PRINTK(a) printk a
-#else
-#define VFC_I2C_DEBUG_PRINTK(a)
-#endif
-
-#endif /* _LINUX_VFC_H_ */
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
deleted file mode 100644 (file)
index 25181bb..0000000
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * drivers/sbus/char/vfc_dev.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * In order to use the VFC you need to program the video controller
- * chip. This chip is the Phillips SAA9051.  You need to call their
- * documentation ordering line to get the docs.
- *
- * There is very little documentation on the VFC itself.  There is
- * some useful info that can be found in the manuals that come with
- * the card.  I will hopefully write some better docs at a later date.
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- * */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/uaccess.h>
-
-#define VFC_MAJOR (60)
-
-#if 0
-#define VFC_IOCTL_DEBUG
-#endif
-
-#include "vfc.h"
-#include <asm/vfc_ioctls.h>
-
-static const struct file_operations vfc_fops;
-static struct vfc_dev **vfc_dev_lst;
-static char vfcstr[]="vfc";
-static unsigned char saa9051_init_array[VFC_SAA9051_NR] = {
-       0x00, 0x64, 0x72, 0x52,
-       0x36, 0x18, 0xff, 0x20,
-       0xfc, 0x77, 0xe3, 0x50,
-       0x3e
-};
-
-static void vfc_lock_device(struct vfc_dev *dev)
-{
-       mutex_lock(&dev->device_lock_mtx);
-}
-
-static void vfc_unlock_device(struct vfc_dev *dev)
-{
-       mutex_unlock(&dev->device_lock_mtx);
-}
-
-
-static void vfc_captstat_reset(struct vfc_dev *dev)
-{
-       dev->control_reg |= VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_CAPTRESET;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static void vfc_memptr_reset(struct vfc_dev *dev)
-{
-       dev->control_reg |= VFC_CONTROL_MEMPTR;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_MEMPTR;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_MEMPTR; 
-       sbus_writel(dev->control_reg, &dev->regs->control);
-}
-
-static int vfc_csr_init(struct vfc_dev *dev)
-{
-       dev->control_reg = 0x80000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       udelay(200); 
-       dev->control_reg &= ~0x80000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       udelay(100); 
-       sbus_writel(0x0f000000, &dev->regs->i2c_magic2);
-
-       vfc_memptr_reset(dev);
-
-       dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       dev->control_reg |= 0x40000000;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-
-       vfc_captstat_reset(dev);
-
-       return 0;
-}
-
-static int vfc_saa9051_init(struct vfc_dev *dev)
-{
-       int i;
-
-       for (i = 0; i < VFC_SAA9051_NR; i++)
-               dev->saa9051_state_array[i] = saa9051_init_array[i];
-
-       vfc_i2c_sendbuf(dev,VFC_SAA9051_ADDR,
-                       dev->saa9051_state_array, VFC_SAA9051_NR);
-       return 0;
-}
-
-static int init_vfc_hw(struct vfc_dev *dev)
-{
-       vfc_lock_device(dev);
-       vfc_csr_init(dev);
-
-       vfc_pcf8584_init(dev);
-       vfc_init_i2c_bus(dev); /* hopefully this doesn't undo the magic
-                                 sun code above*/
-       vfc_saa9051_init(dev);
-       vfc_unlock_device(dev);
-       return 0; 
-}
-
-static int init_vfc_devstruct(struct vfc_dev *dev, int instance)
-{
-       dev->instance=instance;
-       mutex_init(&dev->device_lock_mtx);
-       dev->control_reg=0;
-       dev->busy=0;
-       return 0;
-}
-
-static int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev,
-                          int instance)
-{
-       if(dev == NULL) {
-               printk(KERN_ERR "VFC: Bogus pointer passed\n");
-               return -ENOMEM;
-       }
-       printk("Initializing vfc%d\n",instance);
-       dev->regs = NULL;
-       dev->regs = (volatile struct vfc_regs __iomem *)
-               sbus_ioremap(&sdev->resource[0], 0,
-                            sizeof(struct vfc_regs), vfcstr);
-       dev->which_io = sdev->reg_addrs[0].which_io;
-       dev->phys_regs = (struct vfc_regs *) sdev->reg_addrs[0].phys_addr;
-       if (dev->regs == NULL)
-               return -EIO;
-
-       printk("vfc%d: registers mapped at phys_addr: 0x%lx\n    virt_addr: 0x%lx\n",
-              instance,(unsigned long)sdev->reg_addrs[0].phys_addr,(unsigned long)dev->regs);
-
-       if (init_vfc_devstruct(dev, instance))
-               return -EINVAL;
-       if (init_vfc_hw(dev))
-               return -EIO;
-       return 0;
-}
-
-
-static struct vfc_dev *vfc_get_dev_ptr(int instance)
-{
-       return vfc_dev_lst[instance];
-}
-
-static DEFINE_SPINLOCK(vfc_dev_lock);
-
-static int vfc_open(struct inode *inode, struct file *file) 
-{
-       struct vfc_dev *dev;
-
-       lock_kernel();
-       spin_lock(&vfc_dev_lock);
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if (dev == NULL) {
-               spin_unlock(&vfc_dev_lock);
-               unlock_kernel();
-               return -ENODEV;
-       }
-       if (dev->busy) {
-               spin_unlock(&vfc_dev_lock);
-               unlock_kernel();
-               return -EBUSY;
-       }
-
-       dev->busy = 1;
-       spin_unlock(&vfc_dev_lock);
-
-       vfc_lock_device(dev);
-       
-       vfc_csr_init(dev);
-       vfc_pcf8584_init(dev);
-       vfc_init_i2c_bus(dev);
-       vfc_saa9051_init(dev);
-       vfc_memptr_reset(dev);
-       vfc_captstat_reset(dev);
-       
-       vfc_unlock_device(dev);
-       unlock_kernel();
-       return 0;
-}
-
-static int vfc_release(struct inode *inode,struct file *file) 
-{
-       struct vfc_dev *dev;
-
-       spin_lock(&vfc_dev_lock);
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if (!dev || !dev->busy) {
-               spin_unlock(&vfc_dev_lock);
-               return -EINVAL;
-       }
-       dev->busy = 0;
-       spin_unlock(&vfc_dev_lock);
-       return 0;
-}
-
-static int vfc_debug(struct vfc_dev *dev, int cmd, void __user *argp)
-{
-       struct vfc_debug_inout inout;
-       unsigned char *buffer;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return -EPERM;
-
-       switch(cmd) {
-       case VFC_I2C_SEND:
-               if(copy_from_user(&inout, argp, sizeof(inout)))
-                       return -EFAULT;
-
-               buffer = kmalloc(inout.len, GFP_KERNEL);
-               if (buffer == NULL)
-                       return -ENOMEM;
-
-               if(copy_from_user(buffer, inout.buffer, inout.len)) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               
-
-               vfc_lock_device(dev);
-               inout.ret=
-                       vfc_i2c_sendbuf(dev,inout.addr & 0xff,
-                                       buffer,inout.len);
-
-               if (copy_to_user(argp,&inout,sizeof(inout))) {
-                       vfc_unlock_device(dev);
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               vfc_unlock_device(dev);
-
-               break;
-       case VFC_I2C_RECV:
-               if (copy_from_user(&inout, argp, sizeof(inout)))
-                       return -EFAULT;
-
-               buffer = kzalloc(inout.len, GFP_KERNEL);
-               if (buffer == NULL)
-                       return -ENOMEM;
-
-               vfc_lock_device(dev);
-               inout.ret=
-                       vfc_i2c_recvbuf(dev,inout.addr & 0xff
-                                       ,buffer,inout.len);
-               vfc_unlock_device(dev);
-               
-               if (copy_to_user(inout.buffer, buffer, inout.len)) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               if (copy_to_user(argp,&inout,sizeof(inout))) {
-                       kfree(buffer);
-                       return -EFAULT;
-               }
-               kfree(buffer);
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       return 0;
-}
-
-static int vfc_capture_start(struct vfc_dev *dev)
-{
-       vfc_captstat_reset(dev);
-       dev->control_reg = sbus_readl(&dev->regs->control);
-       if((dev->control_reg & VFC_STATUS_CAPTURE)) {
-               printk(KERN_ERR "vfc%d: vfc capture status not reset\n",
-                      dev->instance);
-               return -EIO;
-       }
-
-       vfc_lock_device(dev);
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg |= VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       dev->control_reg &= ~VFC_CONTROL_CAPTURE;
-       sbus_writel(dev->control_reg, &dev->regs->control);
-       vfc_unlock_device(dev);
-
-       return 0;
-}
-
-static int vfc_capture_poll(struct vfc_dev *dev)
-{
-       int timeout = 1000;
-
-       while (!timeout--) {
-               if (sbus_readl(&dev->regs->control) & VFC_STATUS_CAPTURE)
-                       break;
-               vfc_i2c_delay_no_busy(dev, 100);
-       }
-       if(!timeout) {
-               printk(KERN_WARNING "vfc%d: capture timed out\n",
-                      dev->instance);
-               return -ETIMEDOUT;
-       }
-       return 0;
-}
-
-
-
-static int vfc_set_control_ioctl(struct inode *inode, struct file *file, 
-                         struct vfc_dev *dev, unsigned long arg) 
-{
-       int setcmd, ret = 0;
-
-       if (copy_from_user(&setcmd,(void __user *)arg,sizeof(unsigned int)))
-               return -EFAULT;
-
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSCTRL) arg=0x%x\n",
-                               dev->instance,setcmd));
-
-       switch(setcmd) {
-       case MEMPRST:
-               vfc_lock_device(dev);
-               vfc_memptr_reset(dev);
-               vfc_unlock_device(dev);
-               ret=0;
-               break;
-       case CAPTRCMD:
-               vfc_capture_start(dev);
-               vfc_capture_poll(dev);
-               break;
-       case DIAGMODE:
-               if(capable(CAP_SYS_ADMIN)) {
-                       vfc_lock_device(dev);
-                       dev->control_reg |= VFC_CONTROL_DIAGMODE;
-                       sbus_writel(dev->control_reg, &dev->regs->control);
-                       vfc_unlock_device(dev);
-                       ret = 0;
-               } else {
-                       ret = -EPERM; 
-               }
-               break;
-       case NORMMODE:
-               vfc_lock_device(dev);
-               dev->control_reg &= ~VFC_CONTROL_DIAGMODE;
-               sbus_writel(dev->control_reg, &dev->regs->control);
-               vfc_unlock_device(dev);
-               ret = 0;
-               break;
-       case CAPTRSTR:
-               vfc_capture_start(dev);
-               ret = 0;
-               break;
-       case CAPTRWAIT:
-               vfc_capture_poll(dev);
-               ret = 0;
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       };
-
-       return ret;
-}
-
-
-static int vfc_port_change_ioctl(struct inode *inode, struct file *file,
-                                struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       int cmd;
-
-       if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_port_change_ioctl\n",
-                                       dev->instance));
-               return -EFAULT;
-       }
-       
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCPORTCHG) arg=0x%x\n",
-                               dev->instance, cmd));
-
-       switch(cmd) {
-       case 1:
-       case 2:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x72; 
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x52;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0x36;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0x18;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) = VFC_SAA9051_BP2;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_CT | VFC_SAA9051_SS3;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0x3e;
-               break;
-       case 3:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_START) = 0x3a;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HSY_STOP) = 0x17;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_START) = 0xfa;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HC_STOP) = 0xde;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) =
-                       VFC_SAA9051_BY | VFC_SAA9051_PF | VFC_SAA9051_BP2;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C3) = VFC_SAA9051_YC;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_SECAM_DELAY) = 0;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-                       ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               break;
-       default:
-               ret = -EINVAL;
-               return ret;
-               break;
-       }
-
-       switch(cmd) {
-       case 1:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |=
-                       (VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               break;
-       case 2:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) &=
-                       ~(VFC_SAA9051_SS0 | VFC_SAA9051_SS1);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C2) |= VFC_SAA9051_SS0; 
-               break;
-       case 3:
-               break;
-       default:
-               ret = -EINVAL;
-               return ret;
-               break;
-       }
-       VFC_SAA9051_SA(dev,VFC_SAA9051_C3) &= ~(VFC_SAA9051_SS2);
-       ret=vfc_update_saa9051(dev);
-       udelay(500);
-       VFC_SAA9051_SA(dev,VFC_SAA9051_C3) |= (VFC_SAA9051_SS2);
-       ret=vfc_update_saa9051(dev);
-       return ret;
-}
-
-static int vfc_set_video_ioctl(struct inode *inode, struct file *file,
-                              struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       int cmd;
-
-       if(copy_from_user(&cmd, (void __user *)arg, sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_set_video_ioctl\n",
-                                       dev->instance));
-               return ret;
-       }
-       
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCSVID) arg=0x%x\n",
-                               dev->instance, cmd));
-       switch(cmd) {
-       case STD_NTSC:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~VFC_SAA9051_ALT;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_YPN | 
-                       VFC_SAA9051_CCFR0 | VFC_SAA9051_CCFR1 | VFC_SAA9051_FS;
-               ret = vfc_update_saa9051(dev);
-               break;
-       case STD_PAL:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_YPN | 
-                                                       VFC_SAA9051_CCFR1 | 
-                                                       VFC_SAA9051_CCFR0 |
-                                                       VFC_SAA9051_FS);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_ALT;
-               ret = vfc_update_saa9051(dev);
-               break;
-
-       case COLOR_ON:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) |= VFC_SAA9051_CO;
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) &=
-                       ~(VFC_SAA9051_BY | VFC_SAA9051_PF);
-               ret = vfc_update_saa9051(dev);
-               break;
-       case MONO:
-               VFC_SAA9051_SA(dev,VFC_SAA9051_C1) &= ~(VFC_SAA9051_CO);
-               VFC_SAA9051_SA(dev,VFC_SAA9051_HORIZ_PEAK) |=
-                       (VFC_SAA9051_BY | VFC_SAA9051_PF);
-               ret = vfc_update_saa9051(dev);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_get_video_ioctl(struct inode *inode, struct file *file,
-                              struct vfc_dev *dev, unsigned long arg)
-{
-       int ret = 0;
-       unsigned int status = NO_LOCK;
-       unsigned char buf[1];
-
-       if(vfc_i2c_recvbuf(dev, VFC_SAA9051_ADDR, buf, 1)) {
-               printk(KERN_ERR "vfc%d: Unable to get status\n",
-                      dev->instance);
-               return -EIO;
-       }
-
-       if(buf[0] & VFC_SAA9051_HLOCK) {
-               status = NO_LOCK;
-       } else if(buf[0] & VFC_SAA9051_FD) {
-               if(buf[0] & VFC_SAA9051_CD)
-                       status = NTSC_COLOR;
-               else
-                       status = NTSC_NOCOLOR;
-       } else {
-               if(buf[0] & VFC_SAA9051_CD)
-                       status = PAL_COLOR;
-               else
-                       status = PAL_NOCOLOR;
-       }
-       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGVID) returning status 0x%x; "
-                               "buf[0]=%x\n", dev->instance, status, buf[0]));
-
-       if (copy_to_user((void __user *)arg,&status,sizeof(unsigned int))) {
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer to "
-                                       "vfc_get_video_ioctl\n",
-                                       dev->instance));
-               return ret;
-       }
-       return ret;
-}
-
-static int vfc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-             unsigned long arg) 
-{
-       int ret = 0;
-       unsigned int tmp;
-       struct vfc_dev *dev;
-       void __user *argp = (void __user *)arg;
-
-       dev = vfc_get_dev_ptr(iminor(inode));
-       if(dev == NULL)
-               return -ENODEV;
-       
-       switch(cmd & 0x0000ffff) {
-       case VFCGCTRL:
-#if 0
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCGCTRL)\n", dev->instance));
-#endif
-               tmp = sbus_readl(&dev->regs->control);
-               if(copy_to_user(argp, &tmp, sizeof(unsigned int))) {
-                       ret = -EFAULT;
-                       break;
-               }
-               ret = 0;
-               break;
-       case VFCSCTRL:
-               ret = vfc_set_control_ioctl(inode, file, dev, arg);
-               break;
-       case VFCGVID:
-               ret = vfc_get_video_ioctl(inode, file, dev, arg);
-               break;
-       case VFCSVID:
-               ret = vfc_set_video_ioctl(inode, file, dev, arg);
-               break;
-       case VFCHUE:
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCHUE)\n", dev->instance));
-               if(copy_from_user(&tmp,argp,sizeof(unsigned int))) {
-                       VFC_IOCTL_DEBUG_PRINTK(("vfc%d: User passed bogus pointer "
-                                               "to IOCTL(VFCHUE)", dev->instance));
-                       ret = -EFAULT;
-               } else {
-                       VFC_SAA9051_SA(dev,VFC_SAA9051_HUE) = tmp;
-                       vfc_update_saa9051(dev);
-                       ret = 0;
-               }
-               break;
-       case VFCPORTCHG:
-               ret = vfc_port_change_ioctl(inode, file, dev, arg);
-               break;
-       case VFCRDINFO:
-               ret = -EINVAL;
-               VFC_IOCTL_DEBUG_PRINTK(("vfc%d: IOCTL(VFCRDINFO)\n", dev->instance));
-               break;
-       default:
-               ret = vfc_debug(vfc_get_dev_ptr(iminor(inode)), cmd, argp);
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_mmap(struct file *file, struct vm_area_struct *vma) 
-{
-       unsigned int map_size, ret, map_offset;
-       struct vfc_dev *dev;
-       
-       dev = vfc_get_dev_ptr(iminor(file->f_path.dentry->d_inode));
-       if(dev == NULL)
-               return -ENODEV;
-
-       map_size = vma->vm_end - vma->vm_start;
-       if(map_size > sizeof(struct vfc_regs)) 
-               map_size = sizeof(struct vfc_regs);
-
-       vma->vm_flags |=
-               (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
-       map_offset = (unsigned int) (long)dev->phys_regs;
-       ret = io_remap_pfn_range(vma, vma->vm_start,
-                                 MK_IOSPACE_PFN(dev->which_io,
-                                       map_offset >> PAGE_SHIFT),
-                                 map_size, vma->vm_page_prot);
-
-       if(ret)
-               return -EAGAIN;
-
-       return 0;
-}
-
-
-static const struct file_operations vfc_fops = {
-       .owner =        THIS_MODULE,
-       .llseek =       no_llseek,
-       .ioctl =        vfc_ioctl,
-       .mmap =         vfc_mmap,
-       .open =         vfc_open,
-       .release =      vfc_release,
-};
-
-static int vfc_probe(void)
-{
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev = NULL;
-       int ret;
-       int instance = 0, cards = 0;
-
-       for_all_sbusdev(sdev, sbus) {
-               if (strcmp(sdev->prom_name, "vfc") == 0) {
-                       cards++;
-                       continue;
-               }
-       }
-
-       if (!cards)
-               return -ENODEV;
-
-       vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
-       if (vfc_dev_lst == NULL)
-               return -ENOMEM;
-       vfc_dev_lst[cards] = NULL;
-
-       ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
-       if(ret) {
-               printk(KERN_ERR "Unable to get major number %d\n", VFC_MAJOR);
-               kfree(vfc_dev_lst);
-               return -EIO;
-       }
-       instance = 0;
-       for_all_sbusdev(sdev, sbus) {
-               if (strcmp(sdev->prom_name, "vfc") == 0) {
-                       vfc_dev_lst[instance]=(struct vfc_dev *)
-                               kmalloc(sizeof(struct vfc_dev), GFP_KERNEL);
-                       if (vfc_dev_lst[instance] == NULL)
-                               return -ENOMEM;
-                       ret = init_vfc_device(sdev,
-                                             vfc_dev_lst[instance],
-                                             instance);
-                       if(ret) {
-                               printk(KERN_ERR "Unable to initialize"
-                                      " vfc%d device\n",
-                                      instance);
-                       } else {
-                       }
-               
-                       instance++;
-                       continue;
-               }
-       }
-
-       return 0;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else 
-int vfc_init(void)
-#endif
-{
-       return vfc_probe();
-}
-
-#ifdef MODULE
-static void deinit_vfc_device(struct vfc_dev *dev)
-{
-       if(dev == NULL)
-               return;
-       sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
-       kfree(dev);
-}
-
-void cleanup_module(void)
-{
-       struct vfc_dev **devp;
-
-       unregister_chrdev(VFC_MAJOR,vfcstr);
-
-       for (devp = vfc_dev_lst; *devp; devp++)
-               deinit_vfc_device(*devp);
-
-       kfree(vfc_dev_lst);
-       return;
-}
-#endif
-
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/sbus/char/vfc_i2c.c b/drivers/sbus/char/vfc_i2c.c
deleted file mode 100644 (file)
index 32b986e..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * drivers/sbus/char/vfc_i2c.c
- *
- * Driver for the Videopix Frame Grabber.
- * 
- * Functions that support the Phillips i2c(I squared C) bus on the vfc
- *  Documentation for the Phillips I2C bus can be found on the 
- *  phillips home page
- *
- * Copyright (C) 1996 Manish Vachharajani (mvachhar@noc.rutgers.edu)
- *
- */
-
-/* NOTE: It seems to me that the documentation regarding the
-pcd8584t/pcf8584 does not show the correct way to address the i2c bus.
-Based on the information on the I2C bus itself and the remainder of
-the Phillips docs the following algorithms appear to be correct.  I am
-fairly certain that the flowcharts in the phillips docs are wrong. */
-
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/sbus.h>
-
-#if 0 
-#define VFC_I2C_DEBUG
-#endif
-
-#include "vfc.h"
-#include "vfc_i2c.h"
-
-#define WRITE_S1(__val) \
-       sbus_writel(__val, &dev->regs->i2c_s1)
-#define WRITE_REG(__val) \
-       sbus_writel(__val, &dev->regs->i2c_reg)
-
-#define VFC_I2C_READ (0x1)
-#define VFC_I2C_WRITE (0x0)
-     
-/****** 
-  The i2c bus controller chip on the VFC is a pcd8584t, but
-  phillips claims it doesn't exist.  As far as I can tell it is
-  identical to the PCF8584 so I treat it like it is the pcf8584.
-  
-  NOTE: The pcf8584 only cares
-  about the msb of the word you feed it 
-*****/
-
-int vfc_pcf8584_init(struct vfc_dev *dev) 
-{
-       /* This will also choose register S0_OWN so we can set it. */
-       WRITE_S1(RESET);
-
-       /* The pcf8584 shifts this value left one bit and uses
-        * it as its i2c bus address.
-        */
-       WRITE_REG(0x55000000);
-
-       /* This will set the i2c bus at the same speed sun uses,
-        * and set another magic bit.
-        */
-       WRITE_S1(SELECT(S2));
-       WRITE_REG(0x14000000);
-       
-       /* Enable the serial port, idle the i2c bus and set
-        * the data reg to s0.
-        */
-       WRITE_S1(CLEAR_I2C_BUS);
-       udelay(100);
-       return 0;
-}
-
-void vfc_i2c_delay_no_busy(struct vfc_dev *dev, unsigned long usecs) 
-{
-       schedule_timeout_uninterruptible(usecs_to_jiffies(usecs));
-}
-
-void inline vfc_i2c_delay(struct vfc_dev *dev) 
-{ 
-       vfc_i2c_delay_no_busy(dev, 100);
-}
-
-int vfc_init_i2c_bus(struct vfc_dev *dev)
-{
-       WRITE_S1(ENABLE_SERIAL | SELECT(S0) | ACK);
-       vfc_i2c_reset_bus(dev);
-       return 0;
-}
-
-int vfc_i2c_reset_bus(struct vfc_dev *dev) 
-{
-       VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: Resetting the i2c bus\n",
-                             dev->instance));
-       if(dev == NULL)
-               return -EINVAL;
-       if(dev->regs == NULL)
-               return -EINVAL;
-       WRITE_S1(SEND_I2C_STOP);
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       WRITE_S1(CLEAR_I2C_BUS);
-       VFC_I2C_DEBUG_PRINTK((KERN_DEBUG "vfc%d: I2C status %x\n",
-                             dev->instance,
-                             sbus_readl(&dev->regs->i2c_s1)));
-       return 0;
-}
-
-static int vfc_i2c_wait_for_bus(struct vfc_dev *dev)
-{
-       int timeout = 1000; 
-
-       while(!(sbus_readl(&dev->regs->i2c_s1) & BB)) {
-               if(!(timeout--))
-                       return -ETIMEDOUT;
-               vfc_i2c_delay(dev);
-       }
-       return 0;
-}
-
-static int vfc_i2c_wait_for_pin(struct vfc_dev *dev, int ack)
-{
-       int timeout = 1000; 
-       int s1;
-
-       while ((s1 = sbus_readl(&dev->regs->i2c_s1)) & PIN) {
-               if (!(timeout--))
-                       return -ETIMEDOUT;
-               vfc_i2c_delay(dev);
-       }
-       if (ack == VFC_I2C_ACK_CHECK) {
-               if(s1 & LRB)
-                       return -EIO; 
-       }
-       return 0;
-}
-
-#define SHIFT(a) ((a) << 24)
-static int vfc_i2c_xmit_addr(struct vfc_dev *dev, unsigned char addr,
-                            char mode)
-{ 
-       int ret, raddr;
-#if 1
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       WRITE_S1(SELECT(S0) | ENABLE_SERIAL);
-       vfc_i2c_delay(dev);
-#endif
-
-       switch(mode) {
-       case VFC_I2C_READ:
-               raddr = SHIFT(((unsigned int)addr | 0x1));
-               WRITE_REG(raddr);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: receiving from i2c addr 0x%x\n",
-                                     dev->instance, addr | 0x1));
-               break;
-       case VFC_I2C_WRITE:
-               raddr = SHIFT((unsigned int)addr & ~0x1);
-               WRITE_REG(raddr);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: sending to i2c addr 0x%x\n",
-                                     dev->instance, addr & ~0x1));
-               break;
-       default:
-               return -EINVAL;
-       };
-
-       WRITE_S1(SEND_I2C_START);
-       vfc_i2c_delay(dev);
-       ret = vfc_i2c_wait_for_pin(dev,VFC_I2C_ACK_CHECK); /* We wait
-                                                             for the
-                                                             i2c send
-                                                             to finish
-                                                             here but
-                                                             Sun
-                                                             doesn't,
-                                                             hmm */
-       if (ret) {
-               printk(KERN_ERR "vfc%d: VFC xmit addr timed out or no ack\n",
-                      dev->instance);
-               return ret;
-       } else if (mode == VFC_I2C_READ) {
-               if ((ret = sbus_readl(&dev->regs->i2c_reg) & 0xff000000) != raddr) {
-                       printk(KERN_WARNING 
-                              "vfc%d: returned slave address "
-                              "mismatch(%x,%x)\n",
-                              dev->instance, raddr, ret);
-               }
-       }       
-       return 0;
-}
-
-static int vfc_i2c_xmit_byte(struct vfc_dev *dev,unsigned char *byte)
-{
-       int ret;
-       u32 val = SHIFT((unsigned int)*byte);
-
-       WRITE_REG(val);
-
-       ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_ACK_CHECK); 
-       switch(ret) {
-       case -ETIMEDOUT: 
-               printk(KERN_ERR "vfc%d: VFC xmit byte timed out or no ack\n",
-                      dev->instance);
-               break;
-       case -EIO:
-               ret = XMIT_LAST_BYTE;
-               break;
-       default:
-               break;
-       };
-
-       return ret;
-}
-
-static int vfc_i2c_recv_byte(struct vfc_dev *dev, unsigned char *byte,
-                            int last)
-{
-       int ret;
-
-       if (last) {
-               WRITE_REG(NEGATIVE_ACK);
-               VFC_I2C_DEBUG_PRINTK(("vfc%d: sending negative ack\n",
-                                     dev->instance));
-       } else {
-               WRITE_S1(ACK);
-       }
-
-       ret = vfc_i2c_wait_for_pin(dev, VFC_I2C_NO_ACK_CHECK);
-       if(ret) {
-               printk(KERN_ERR "vfc%d: "
-                      "VFC recv byte timed out\n",
-                      dev->instance);
-       }
-       *byte = (sbus_readl(&dev->regs->i2c_reg)) >> 24;
-       return ret;
-}
-
-int vfc_i2c_recvbuf(struct vfc_dev *dev, unsigned char addr,
-                   char *buf, int count)
-{
-       int ret, last;
-
-       if(!(count && buf && dev && dev->regs) )
-               return -EINVAL;
-
-       if ((ret = vfc_i2c_wait_for_bus(dev))) {
-               printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-               return ret;
-       }
-
-       if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_READ))) {
-               WRITE_S1(SEND_I2C_STOP);
-               vfc_i2c_delay(dev);
-               return ret;
-       }
-       
-       last = 0;
-       while (count--) {
-               if (!count)
-                       last = 1;
-               if ((ret = vfc_i2c_recv_byte(dev, buf, last))) {
-                       printk(KERN_ERR "vfc%d: "
-                              "VFC error while receiving byte\n",
-                              dev->instance);
-                       WRITE_S1(SEND_I2C_STOP);
-                       ret = -EINVAL;
-               }
-               buf++;
-       }
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       return ret;
-}
-
-int vfc_i2c_sendbuf(struct vfc_dev *dev, unsigned char addr, 
-                   char *buf, int count) 
-{
-       int ret;
-       
-       if (!(buf && dev && dev->regs))
-               return -EINVAL;
-       
-       if ((ret = vfc_i2c_wait_for_bus(dev))) {
-               printk(KERN_ERR "vfc%d: VFC I2C bus busy\n", dev->instance);
-               return ret;
-       }
-       
-       if ((ret = vfc_i2c_xmit_addr(dev, addr, VFC_I2C_WRITE))) {
-               WRITE_S1(SEND_I2C_STOP);
-               vfc_i2c_delay(dev);
-               return ret;
-       }
-       
-       while(count--) {
-               ret = vfc_i2c_xmit_byte(dev, buf);
-               switch(ret) {
-               case XMIT_LAST_BYTE:
-                       VFC_I2C_DEBUG_PRINTK(("vfc%d: "
-                                             "Receiver ended transmission with "
-                                             " %d bytes remaining\n",
-                                             dev->instance, count));
-                       ret = 0;
-                       goto done;
-                       break;
-               case 0:
-                       break;
-               default:
-                       printk(KERN_ERR "vfc%d: "
-                              "VFC error while sending byte\n", dev->instance);
-                       break;
-               };
-
-               buf++;
-       }
-done:
-       WRITE_S1(SEND_I2C_STOP | ACK);
-       vfc_i2c_delay(dev);
-       return ret;
-}
-
-
-
-
-
-
-
-
-
diff --git a/drivers/sbus/char/vfc_i2c.h b/drivers/sbus/char/vfc_i2c.h
deleted file mode 100644 (file)
index a2e6973..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef _LINUX_VFC_I2C_H_
-#define _LINUX_VFC_I2C_H_
-
-/* control bits */
-#define PIN  (0x80000000)
-#define ESO  (0x40000000)
-#define ES1  (0x20000000)
-#define ES2  (0x10000000)
-#define ENI  (0x08000000)
-#define STA  (0x04000000)
-#define STO  (0x02000000)
-#define ACK  (0x01000000)
-
-/* status bits */
-#define STS  (0x20000000)
-#define BER  (0x10000000)
-#define LRB  (0x08000000)
-#define AAS  (0x04000000)
-#define LAB  (0x02000000)
-#define BB   (0x01000000)
-
-#define SEND_I2C_START (PIN | ESO | STA)
-#define SEND_I2C_STOP (PIN | ESO | STO)
-#define CLEAR_I2C_BUS (PIN | ESO | ACK)
-#define NEGATIVE_ACK ((ESO) & ~ACK)
-
-#define SELECT(a) (a)
-#define S0 (PIN | ESO | ES1)
-#define S0_OWN (PIN)
-#define S2 (PIN | ES1)
-#define S3 (PIN | ES2)
-
-#define ENABLE_SERIAL (PIN | ESO)
-#define DISABLE_SERIAL (PIN)
-#define RESET (PIN)
-
-#define XMIT_LAST_BYTE (1)
-#define VFC_I2C_ACK_CHECK (1)
-#define VFC_I2C_NO_ACK_CHECK (0)
-
-#endif /* _LINUX_VFC_I2C_H_ */
-
-
-
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
deleted file mode 100644 (file)
index ab0d2de..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/* dvma.c:  Routines that are used to access DMA on the Sparc SBus.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/oplib.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/sbus.h>
-
-struct sbus_dma *dma_chain;
-
-static void __init init_one_dvma(struct sbus_dma *dma, int num_dma)
-{
-       printk("dma%d: ", num_dma);
-       
-       dma->next = NULL;
-       dma->running = 0;      /* No transfers going on as of yet */
-       dma->allocated = 0;    /* No one has allocated us yet */
-       switch(sbus_readl(dma->regs + DMA_CSR)&DMA_DEVICE_ID) {
-       case DMA_VERS0:
-               dma->revision = dvmarev0;
-               printk("Revision 0 ");
-               break;
-       case DMA_ESCV1:
-               dma->revision = dvmaesc1;
-               printk("ESC Revision 1 ");
-               break;
-       case DMA_VERS1:
-               dma->revision = dvmarev1;
-               printk("Revision 1 ");
-               break;
-       case DMA_VERS2:
-               dma->revision = dvmarev2;
-               printk("Revision 2 ");
-               break;
-       case DMA_VERHME:
-               dma->revision = dvmahme;
-               printk("HME DVMA gate array ");
-               break;
-       case DMA_VERSPLUS:
-               dma->revision = dvmarevplus;
-               printk("Revision 1 PLUS ");
-               break;
-       default:
-               printk("unknown dma version %08x",
-                      sbus_readl(dma->regs + DMA_CSR) & DMA_DEVICE_ID);
-               dma->allocated = 1;
-               break;
-       }
-       printk("\n");
-}
-
-/* Probe this SBus DMA module(s) */
-void __init dvma_init(struct sbus_bus *sbus)
-{
-       struct sbus_dev *this_dev;
-       struct sbus_dma *dma;
-       struct sbus_dma *dchain;
-       static int num_dma = 0;
-
-       for_each_sbusdev(this_dev, sbus) {
-               char *name = this_dev->prom_name;
-               int hme = 0;
-
-               if(!strcmp(name, "SUNW,fas"))
-                       hme = 1;
-               else if(strcmp(name, "dma") &&
-                       strcmp(name, "ledma") &&
-                       strcmp(name, "espdma"))
-                       continue;
-
-               /* Found one... */
-               dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-               dma->sdev = this_dev;
-
-               /* Put at end of dma chain */
-               dchain = dma_chain;
-               if(dchain) {
-                       while(dchain->next)
-                               dchain = dchain->next;
-                       dchain->next = dma;
-               } else {
-                       /* We're the first in line */
-                       dma_chain = dma;
-               }
-
-               dma->regs = sbus_ioremap(&dma->sdev->resource[0], 0,
-                                        dma->sdev->resource[0].end - dma->sdev->resource[0].start + 1,
-                                        "dma");
-
-               dma->node = dma->sdev->prom_node;
-               
-               init_one_dvma(dma, num_dma++);
-       }
-}
-
-#ifdef CONFIG_SUN4
-
-#include <asm/sun4paddr.h>
-
-void __init sun4_dvma_init(void)
-{
-       struct sbus_dma *dma;
-       struct resource r;
-
-       if(sun4_dma_physaddr) {
-               dma = kmalloc(sizeof(struct sbus_dma), GFP_ATOMIC);
-
-               /* No SBUS */
-               dma->sdev = NULL;
-
-               /* Only one DMA device */
-               dma_chain = dma;
-
-               memset(&r, 0, sizeof(r));
-               r.start = sun4_dma_physaddr;
-               dma->regs = sbus_ioremap(&r, 0, PAGE_SIZE, "dma");
-
-               /* No prom node */
-               dma->node = 0x0;
-
-               init_one_dvma(dma, 0);
-       } else {
-               dma_chain = NULL;
-       }
-}
-
-#endif
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
deleted file mode 100644 (file)
index 9c12924..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/* sbus.c: SBus support routines.
- *
- * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/of_device.h>
-
-#include <asm/system.h>
-#include <asm/sbus.h>
-#include <asm/dma.h>
-#include <asm/oplib.h>
-#include <asm/prom.h>
-#include <asm/bpp.h>
-#include <asm/irq.h>
-
-static ssize_t
-show_sbusobppath_attr(struct device * dev, struct device_attribute * attr, char * buf)
-{
-       struct sbus_dev *sbus;
-
-       sbus = to_sbus_device(dev);
-
-       return snprintf (buf, PAGE_SIZE, "%s\n", sbus->ofdev.node->full_name);
-}
-
-static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH, show_sbusobppath_attr, NULL);
-
-struct sbus_bus *sbus_root;
-
-static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
-{
-       struct dev_archdata *sd;
-       unsigned long base;
-       const void *pval;
-       int len, err;
-
-       sdev->prom_node = dp->node;
-       strcpy(sdev->prom_name, dp->name);
-
-       pval = of_get_property(dp, "reg", &len);
-       sdev->num_registers = 0;
-       if (pval) {
-               memcpy(sdev->reg_addrs, pval, len);
-
-               sdev->num_registers =
-                       len / sizeof(struct linux_prom_registers);
-
-               base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-
-               /* Compute the slot number. */
-               if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
-                       sdev->slot = sbus_dev_slot(base);
-               else
-                       sdev->slot = sdev->reg_addrs[0].which_io;
-       }
-
-       pval = of_get_property(dp, "ranges", &len);
-       sdev->num_device_ranges = 0;
-       if (pval) {
-               memcpy(sdev->device_ranges, pval, len);
-               sdev->num_device_ranges =
-                       len / sizeof(struct linux_prom_ranges);
-       }
-
-       sbus_fill_device_irq(sdev);
-
-       sd = &sdev->ofdev.dev.archdata;
-       sd->prom_node = dp;
-       sd->op = &sdev->ofdev;
-
-       sdev->ofdev.node = dp;
-       if (sdev->parent)
-               sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
-       else
-               sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
-       sdev->ofdev.dev.bus = &sbus_bus_type;
-       dev_set_name(&sdev->ofdev.dev, "sbus[%08x]", dp->node);
-
-       if (of_device_register(&sdev->ofdev) != 0)
-               printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-                      dp->path_component_name);
-
-       /* WE HAVE BEEN INVADED BY ALIENS! */
-       err = sysfs_create_file(&sdev->ofdev.dev.kobj, &dev_attr_obppath.attr);
-}
-
-static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
-{
-       const void *pval;
-       int len;
-
-       pval = of_get_property(dp, "ranges", &len);
-       sbus->num_sbus_ranges = 0;
-       if (pval) {
-               memcpy(sbus->sbus_ranges, pval, len);
-               sbus->num_sbus_ranges =
-                       len / sizeof(struct linux_prom_ranges);
-
-               sbus_arch_bus_ranges_init(dp->parent, sbus);
-       }
-}
-
-static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
-                                         int num_ranges,
-                                         struct linux_prom_registers *regs,
-                                         int num_regs)
-{
-       if (num_ranges) {
-               int regnum;
-
-               for (regnum = 0; regnum < num_regs; regnum++) {
-                       int rngnum;
-
-                       for (rngnum = 0; rngnum < num_ranges; rngnum++) {
-                               if (regs[regnum].which_io == ranges[rngnum].ot_child_space)
-                                       break;
-                       }
-                       if (rngnum == num_ranges) {
-                               /* We used to flag this as an error.  Actually
-                                * some devices do not report the regs as we expect.
-                                * For example, see SUNW,pln device.  In that case
-                                * the reg property is in a format internal to that
-                                * node, ie. it is not in the SBUS register space
-                                * per se. -DaveM
-                                */
-                               return;
-                       }
-                       regs[regnum].which_io = ranges[rngnum].ot_parent_space;
-                       regs[regnum].phys_addr -= ranges[rngnum].ot_child_base;
-                       regs[regnum].phys_addr += ranges[rngnum].ot_parent_base;
-               }
-       }
-}
-
-static void __init __fixup_regs_sdev(struct sbus_dev *sdev)
-{
-       if (sdev->num_registers != 0) {
-               struct sbus_dev *parent = sdev->parent;
-               int i;
-
-               while (parent != NULL) {
-                       __apply_ranges_to_regs(parent->device_ranges,
-                                              parent->num_device_ranges,
-                                              sdev->reg_addrs,
-                                              sdev->num_registers);
-
-                       parent = parent->parent;
-               }
-
-               __apply_ranges_to_regs(sdev->bus->sbus_ranges,
-                                      sdev->bus->num_sbus_ranges,
-                                      sdev->reg_addrs,
-                                      sdev->num_registers);
-
-               for (i = 0; i < sdev->num_registers; i++) {
-                       struct resource *res = &sdev->resource[i];
-
-                       res->start = sdev->reg_addrs[i].phys_addr;
-                       res->end = (res->start +
-                                   (unsigned long)sdev->reg_addrs[i].reg_size - 1UL);
-                       res->flags = IORESOURCE_IO |
-                               (sdev->reg_addrs[i].which_io & 0xff);
-               }
-       }
-}
-
-static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
-{
-       struct sbus_dev *sdev;
-
-       for (sdev = first_sdev; sdev; sdev = sdev->next) {
-               if (sdev->child)
-                       sbus_fixup_all_regs(sdev->child);
-               __fixup_regs_sdev(sdev);
-       }
-}
-
-/* We preserve the "probe order" of these bus and device lists to give
- * the same ordering as the old code.
- */
-static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
-{
-       while (*root)
-               root = &(*root)->next;
-       *root = sbus;
-       sbus->next = NULL;
-}
-
-static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
-{
-       while (*root)
-               root = &(*root)->next;
-       *root = sdev;
-       sdev->next = NULL;
-}
-
-static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
-{
-       dp = dp->child;
-       while (dp) {
-               struct sbus_dev *sdev;
-
-               sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-               if (sdev) {
-                       sdev_insert(sdev, &parent->child);
-
-                       sdev->bus = sbus;
-                       sdev->parent = parent;
-                       sdev->ofdev.dev.archdata.iommu =
-                               sbus->ofdev.dev.archdata.iommu;
-                       sdev->ofdev.dev.archdata.stc =
-                               sbus->ofdev.dev.archdata.stc;
-
-                       fill_sbus_device(dp, sdev);
-
-                       walk_children(dp, sdev, sbus);
-               }
-               dp = dp->sibling;
-       }
-}
-
-static void __init build_one_sbus(struct device_node *dp, int num_sbus)
-{
-       struct sbus_bus *sbus;
-       unsigned int sbus_clock;
-       struct device_node *dev_dp;
-
-       sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
-       if (!sbus)
-               return;
-
-       sbus_insert(sbus, &sbus_root);
-       sbus->prom_node = dp->node;
-
-       sbus_setup_iommu(sbus, dp);
-
-       printk("sbus%d: ", num_sbus);
-
-       sbus_clock = of_getintprop_default(dp, "clock-frequency",
-                                          (25*1000*1000));
-       sbus->clock_freq = sbus_clock;
-
-       printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
-              (int) (((sbus_clock/1000)%1000 != 0) ? 
-                     (((sbus_clock/1000)%1000) + 1000) : 0));
-
-       strcpy(sbus->prom_name, dp->name);
-
-       sbus_setup_arch_props(sbus, dp);
-
-       sbus_bus_ranges_init(dp, sbus);
-
-       sbus->ofdev.node = dp;
-       sbus->ofdev.dev.parent = NULL;
-       sbus->ofdev.dev.bus = &sbus_bus_type;
-       dev_set_name(&sbus->ofdev.dev, "sbus%d", num_sbus);
-
-       if (of_device_register(&sbus->ofdev) != 0)
-               printk(KERN_DEBUG "sbus: device registration error for %s!\n",
-                      dev_name(&sbus->ofdev.dev));
-
-       dev_dp = dp->child;
-       while (dev_dp) {
-               struct sbus_dev *sdev;
-
-               sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-               if (sdev) {
-                       sdev_insert(sdev, &sbus->devices);
-
-                       sdev->bus = sbus;
-                       sdev->parent = NULL;
-                       sdev->ofdev.dev.archdata.iommu =
-                               sbus->ofdev.dev.archdata.iommu;
-                       sdev->ofdev.dev.archdata.stc =
-                               sbus->ofdev.dev.archdata.stc;
-
-                       fill_sbus_device(dev_dp, sdev);
-
-                       walk_children(dev_dp, sdev, sbus);
-               }
-               dev_dp = dev_dp->sibling;
-       }
-
-       sbus_fixup_all_regs(sbus->devices);
-
-       dvma_init(sbus);
-}
-
-static int __init sbus_init(void)
-{
-       struct device_node *dp;
-       const char *sbus_name = "sbus";
-       int num_sbus = 0;
-
-       if (sbus_arch_preinit())
-               return 0;
-
-       if (sparc_cpu_model == sun4d)
-               sbus_name = "sbi";
-
-       for_each_node_by_name(dp, sbus_name) {
-               build_one_sbus(dp, num_sbus);
-               num_sbus++;
-
-       }
-
-       sbus_arch_postinit();
-
-       return 0;
-}
-
-subsys_initcall(sbus_init);
index bb43a138818805d6d3ca683c2c75ce27cef4d87e..28e22acf87ea94f9c703086689da850174495573 100644 (file)
@@ -521,7 +521,8 @@ struct esp {
 
        struct completion       *eh_reset;
 
-       struct sbus_dma         *dma;
+       void                    *dma;
+       int                     dmarev;
 };
 
 /* A front-end driver for the ESP chip should do the following in
index 9053508967253b9d894efefbd81bdc1bf125e725..69d6ad862b60f3eb7af0e69ca1e415786a9ea84c 100644 (file)
@@ -1,6 +1,6 @@
 /* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
  *
- * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net)
  *
  * A lot of this driver was directly stolen from Erik H. Moe's PCI
  * Qlogic ISP driver.  Mucho kudos to him for this code.
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/jiffies.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/byteorder.h>
 
 #include "qlogicpti.h"
 
-#include <asm/sbus.h>
 #include <asm/dma.h>
 #include <asm/system.h>
 #include <asm/ptrace.h>
@@ -157,7 +159,7 @@ static inline void set_sbus_cfg1(struct qlogicpti *qpti)
         * is a nop and the chip ends up using the smallest burst
         * size. -DaveM
         */
-       if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+       if (sbus_can_burst64() && (bursts & DMA_BURST64)) {
                val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
        } else
 #endif
@@ -684,19 +686,19 @@ static void __devexit qpti_chain_del(struct qlogicpti *qpti)
 
 static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
-       qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
-                                  sdev->reg_addrs[0].reg_size,
-                                  "PTI Qlogic/ISP");
+       qpti->qregs = of_ioremap(&op->resource[0], 0,
+                                resource_size(&op->resource[0]),
+                                "PTI Qlogic/ISP");
        if (!qpti->qregs) {
                printk("PTI: Qlogic/ISP registers are unmappable\n");
                return -1;
        }
        if (qpti->is_pti) {
-               qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
-                                         sizeof(unsigned char),
-                                         "PTI Qlogic/ISP statreg");
+               qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096),
+                                       sizeof(unsigned char),
+                                       "PTI Qlogic/ISP statreg");
                if (!qpti->sreg) {
                        printk("PTI: Qlogic/ISP status register is unmappable\n");
                        return -1;
@@ -707,9 +709,9 @@ static int __devinit qpti_map_regs(struct qlogicpti *qpti)
 
 static int __devinit qpti_register_irq(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
-       qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+       qpti->qhost->irq = qpti->irq = op->irqs[0];
 
        /* We used to try various overly-clever things to
         * reduce the interrupt processing overhead on
@@ -732,17 +734,19 @@ fail:
 
 static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 {
-       qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-                                          "initiator-id",
-                                          -1);
+       struct of_device *op = qpti->op;
+       struct device_node *dp;
+
+       dp = op->node;
+
+       qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1);
        if (qpti->scsi_id == -1)
-               qpti->scsi_id = prom_getintdefault(qpti->prom_node,
-                                                  "scsi-initiator-id",
-                                                  -1);
+               qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id",
+                                                     -1);
        if (qpti->scsi_id == -1)
                qpti->scsi_id =
-                       prom_getintdefault(qpti->sdev->bus->prom_node,
-                                          "scsi-initiator-id", 7);
+                       of_getintprop_default(dp->parent,
+                                             "scsi-initiator-id", 7);
        qpti->qhost->this_id = qpti->scsi_id;
        qpti->qhost->max_sectors = 64;
 
@@ -751,12 +755,11 @@ static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti)
 
 static void qpti_get_bursts(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
        u8 bursts, bmask;
 
-       bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
-       bmask = prom_getintdefault(sdev->bus->prom_node,
-                                  "burst-sizes", 0xff);
+       bursts = of_getintprop_default(op->node, "burst-sizes", 0xff);
+       bmask = of_getintprop_default(op->node->parent, "burst-sizes", 0xff);
        if (bmask != 0xff)
                bursts &= bmask;
        if (bursts == 0xff ||
@@ -785,25 +788,25 @@ static void qpti_get_clock(struct qlogicpti *qpti)
  */
 static int __devinit qpti_map_queues(struct qlogicpti *qpti)
 {
-       struct sbus_dev *sdev = qpti->sdev;
+       struct of_device *op = qpti->op;
 
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       qpti->res_cpu = sbus_alloc_consistent(sdev,
-                                             QSIZE(RES_QUEUE_LEN),
-                                             &qpti->res_dvma);
+       qpti->res_cpu = dma_alloc_coherent(&op->dev,
+                                          QSIZE(RES_QUEUE_LEN),
+                                          &qpti->res_dvma, GFP_ATOMIC);
        if (qpti->res_cpu == NULL ||
            qpti->res_dvma == 0) {
                printk("QPTI: Cannot map response queue.\n");
                return -1;
        }
 
-       qpti->req_cpu = sbus_alloc_consistent(sdev,
-                                             QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                                             &qpti->req_dvma);
+       qpti->req_cpu = dma_alloc_coherent(&op->dev,
+                                          QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                                          &qpti->req_dvma, GFP_ATOMIC);
        if (qpti->req_cpu == NULL ||
            qpti->req_dvma == 0) {
-               sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
-                                    qpti->res_cpu, qpti->res_dvma);
+               dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN),
+                                 qpti->res_cpu, qpti->res_dvma);
                printk("QPTI: Cannot map request queue.\n");
                return -1;
        }
@@ -875,8 +878,9 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
                int sg_count;
 
                sg = scsi_sglist(Cmnd);
-               sg_count = sbus_map_sg(qpti->sdev, sg, scsi_sg_count(Cmnd),
-                                                     Cmnd->sc_data_direction);
+               sg_count = dma_map_sg(&qpti->op->dev, sg,
+                                     scsi_sg_count(Cmnd),
+                                     Cmnd->sc_data_direction);
 
                ds = cmd->dataseg;
                cmd->segment_cnt = sg_count;
@@ -1152,9 +1156,9 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
                        Cmnd->result = DID_ERROR << 16;
 
                if (scsi_bufflen(Cmnd))
-                       sbus_unmap_sg(qpti->sdev,
-                                     scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
-                                     Cmnd->sc_data_direction);
+                       dma_unmap_sg(&qpti->op->dev,
+                                    scsi_sglist(Cmnd), scsi_sg_count(Cmnd),
+                                    Cmnd->sc_data_direction);
 
                qpti->cmd_count[Cmnd->device->id]--;
                sbus_writew(out_ptr, qpti->qregs + MBOX5);
@@ -1268,34 +1272,32 @@ static struct scsi_host_template qpti_template = {
        .use_clustering         = ENABLE_CLUSTERING,
 };
 
-static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit qpti_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       static int nqptis;
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
        struct scsi_host_template *tpnt = match->data;
+       struct device_node *dp = op->node;
        struct Scsi_Host *host;
        struct qlogicpti *qpti;
+       static int nqptis;
        const char *fcode;
 
        /* Sometimes Antares cards come up not completely
         * setup, and we get a report of a zero IRQ.
         */
-       if (sdev->irqs[0] == 0)
+       if (op->irqs[0] == 0)
                return -ENODEV;
 
        host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
        if (!host)
                return -ENOMEM;
 
-       qpti = (struct qlogicpti *) host->hostdata;
+       qpti = shost_priv(host);
 
        host->max_id = MAX_TARGETS;
        qpti->qhost = host;
-       qpti->sdev = sdev;
+       qpti->op = op;
        qpti->qpti_id = nqptis;
-       qpti->prom_node = sdev->prom_node;
-       strcpy(qpti->prom_name, sdev->ofdev.node->name);
+       strcpy(qpti->prom_name, op->node->name);
        qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
 
        if (qpti_map_regs(qpti) < 0)
@@ -1341,12 +1343,12 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
                (qpti->ultra ? "Ultra" : "Fast"),
                (qpti->differential ? "differential" : "single ended"));
 
-       if (scsi_add_host(host, &dev->dev)) {
+       if (scsi_add_host(host, &op->dev)) {
                printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
                goto fail_unmap_queues;
        }
 
-       dev_set_drvdata(&sdev->ofdev.dev, qpti);
+       dev_set_drvdata(&op->dev, qpti);
 
        qpti_chain_add(qpti);
 
@@ -1357,19 +1359,20 @@ static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_devi
 
 fail_unmap_queues:
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(RES_QUEUE_LEN),
-                            qpti->res_cpu, qpti->res_dvma);
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                            qpti->req_cpu, qpti->req_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(RES_QUEUE_LEN),
+                         qpti->res_cpu, qpti->res_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                         qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
 fail_unmap_regs:
-       sbus_iounmap(qpti->qregs,
-                    qpti->sdev->reg_addrs[0].reg_size);
+       of_iounmap(&op->resource[0], qpti->qregs,
+                  resource_size(&op->resource[0]));
        if (qpti->is_pti)
-               sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+               of_iounmap(&op->resource[0], qpti->sreg,
+                          sizeof(unsigned char));
 
 fail_free_irq:
        free_irq(qpti->irq, qpti);
@@ -1380,9 +1383,9 @@ fail_unlink:
        return -ENODEV;
 }
 
-static int __devexit qpti_sbus_remove(struct of_device *dev)
+static int __devexit qpti_sbus_remove(struct of_device *op)
 {
-       struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+       struct qlogicpti *qpti = dev_get_drvdata(&op->dev);
 
        qpti_chain_del(qpti);
 
@@ -1395,24 +1398,25 @@ static int __devexit qpti_sbus_remove(struct of_device *dev)
        free_irq(qpti->irq, qpti);
 
 #define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(RES_QUEUE_LEN),
-                            qpti->res_cpu, qpti->res_dvma);
-       sbus_free_consistent(qpti->sdev,
-                            QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
-                            qpti->req_cpu, qpti->req_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(RES_QUEUE_LEN),
+                         qpti->res_cpu, qpti->res_dvma);
+       dma_free_coherent(&op->dev,
+                         QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+                         qpti->req_cpu, qpti->req_dvma);
 #undef QSIZE
 
-       sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+       of_iounmap(&op->resource[0], qpti->qregs,
+                  resource_size(&op->resource[0]));
        if (qpti->is_pti)
-               sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+               of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char));
 
        scsi_host_put(qpti->qhost);
 
        return 0;
 }
 
-static struct of_device_id qpti_match[] = {
+static const struct of_device_id qpti_match[] = {
        {
                .name = "ptisp",
                .data = &qpti_template,
@@ -1442,7 +1446,7 @@ static struct of_platform_driver qpti_sbus_driver = {
 
 static int __init qpti_init(void)
 {
-       return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&qpti_sbus_driver, &of_bus_type);
 }
 
 static void __exit qpti_exit(void)
@@ -1453,7 +1457,7 @@ static void __exit qpti_exit(void)
 MODULE_DESCRIPTION("QlogicISP SBUS driver");
 MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
 MODULE_LICENSE("GPL");
-MODULE_VERSION("2.0");
+MODULE_VERSION("2.1");
 
 module_init(qpti_init);
 module_exit(qpti_exit);
index ef6da2df584ba29fbfddcbb19e105d0fe7b1a319..9c053bbaa87700b375539138b96648bda15366be 100644 (file)
@@ -342,7 +342,7 @@ struct qlogicpti {
        u_int                     req_in_ptr;           /* index of next request slot */
        u_int                     res_out_ptr;          /* index of next result slot  */
        long                      send_marker;          /* must we send a marker?     */
-       struct sbus_dev          *sdev;
+       struct of_device         *op;
        unsigned long             __pad;
 
        int                       cmd_count[MAX_TARGETS];
index f9cf7015136648380aa6bc86f18809ed3eacd2c5..3d73aad4bc8201196946e2a1e2c19e4e98157327 100644 (file)
@@ -1,6 +1,6 @@
 /* sun_esp.c: ESP front-end for Sparc SBUS systems.
  *
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
@@ -9,60 +9,70 @@
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <asm/sbus.h>
-
 #include <scsi/scsi_host.h>
 
 #include "esp_scsi.h"
 
 #define DRV_MODULE_NAME                "sun_esp"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_VERSION            "1.000"
-#define DRV_MODULE_RELDATE     "April 19, 2007"
+#define DRV_VERSION            "1.100"
+#define DRV_MODULE_RELDATE     "August 27, 2008"
 
 #define dma_read32(REG) \
        sbus_readl(esp->dma_regs + (REG))
 #define dma_write32(VAL, REG) \
        sbus_writel((VAL), esp->dma_regs + (REG))
 
-static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sdev)
-{
-       struct sbus_dev *sdev = esp->dev;
-       struct sbus_dma *dma;
+/* DVMA chip revisions */
+enum dvma_rev {
+       dvmarev0,
+       dvmaesc1,
+       dvmarev1,
+       dvmarev2,
+       dvmarev3,
+       dvmarevplus,
+       dvmahme
+};
 
-       if (dma_sdev != NULL) {
-               for_each_dvma(dma) {
-                       if (dma->sdev == dma_sdev)
-                               break;
-               }
-       } else {
-               for_each_dvma(dma) {
-                       if (dma->sdev == NULL)
-                               break;
+static int __devinit esp_sbus_setup_dma(struct esp *esp,
+                                       struct of_device *dma_of)
+{
+       esp->dma = dma_of;
 
-                       /* If bus + slot are the same and it has the
-                        * correct OBP name, it's ours.
-                        */
-                       if (sdev->bus == dma->sdev->bus &&
-                           sdev->slot == dma->sdev->slot &&
-                           (!strcmp(dma->sdev->prom_name, "dma") ||
-                            !strcmp(dma->sdev->prom_name, "espdma")))
-                               break;
-               }
-       }
+       esp->dma_regs = of_ioremap(&dma_of->resource[0], 0,
+                                  resource_size(&dma_of->resource[0]),
+                                  "espdma");
+       if (!esp->dma_regs)
+               return -ENOMEM;
 
-       if (dma == NULL) {
-               printk(KERN_ERR PFX "[%s] Cannot find dma.\n",
-                      sdev->ofdev.node->full_name);
-               return -ENODEV;
+       switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) {
+       case DMA_VERS0:
+               esp->dmarev = dvmarev0;
+               break;
+       case DMA_ESCV1:
+               esp->dmarev = dvmaesc1;
+               break;
+       case DMA_VERS1:
+               esp->dmarev = dvmarev1;
+               break;
+       case DMA_VERS2:
+               esp->dmarev = dvmarev2;
+               break;
+       case DMA_VERHME:
+               esp->dmarev = dvmahme;
+               break;
+       case DMA_VERSPLUS:
+               esp->dmarev = dvmarevplus;
+               break;
        }
-       esp->dma = dma;
-       esp->dma_regs = dma->regs;
 
        return 0;
 
@@ -70,18 +80,18 @@ static int __devinit esp_sbus_find_dma(struct esp *esp, struct sbus_dev *dma_sde
 
 static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 {
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
        struct resource *res;
 
        /* On HME, two reg sets exist, first is DVMA,
         * second is ESP registers.
         */
        if (hme)
-               res = &sdev->resource[1];
+               res = &op->resource[1];
        else
-               res = &sdev->resource[0];
+               res = &op->resource[0];
 
-       esp->regs = sbus_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
+       esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP");
        if (!esp->regs)
                return -ENOMEM;
 
@@ -90,10 +100,11 @@ static int __devinit esp_sbus_map_regs(struct esp *esp, int hme)
 
 static int __devinit esp_sbus_map_command_block(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
 
-       esp->command_block = sbus_alloc_consistent(sdev, 16,
-                                                  &esp->command_block_dma);
+       esp->command_block = dma_alloc_coherent(&op->dev, 16,
+                                               &esp->command_block_dma,
+                                               GFP_ATOMIC);
        if (!esp->command_block)
                return -ENOMEM;
        return 0;
@@ -102,17 +113,18 @@ static int __devinit esp_sbus_map_command_block(struct esp *esp)
 static int __devinit esp_sbus_register_irq(struct esp *esp)
 {
        struct Scsi_Host *host = esp->host;
-       struct sbus_dev *sdev = esp->dev;
+       struct of_device *op = esp->dev;
 
-       host->irq = sdev->irqs[0];
+       host->irq = op->irqs[0];
        return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp);
 }
 
-static void __devinit esp_get_scsi_id(struct esp *esp)
+static void __devinit esp_get_scsi_id(struct esp *esp, struct of_device *espdma)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
 
+       dp = op->node;
        esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff);
        if (esp->scsi_id != 0xff)
                goto done;
@@ -121,13 +133,7 @@ static void __devinit esp_get_scsi_id(struct esp *esp)
        if (esp->scsi_id != 0xff)
                goto done;
 
-       if (!sdev->bus) {
-               /* SUN4 */
-               esp->scsi_id = 7;
-               goto done;
-       }
-
-       esp->scsi_id = of_getintprop_default(sdev->bus->ofdev.node,
+       esp->scsi_id = of_getintprop_default(espdma->node,
                                             "scsi-initiator-id", 7);
 
 done:
@@ -137,9 +143,10 @@ done:
 
 static void __devinit esp_get_differential(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
 
+       dp = op->node;
        if (of_find_property(dp, "differential", NULL))
                esp->flags |= ESP_FLAG_DIFFERENTIAL;
        else
@@ -148,43 +155,36 @@ static void __devinit esp_get_differential(struct esp *esp)
 
 static void __devinit esp_get_clock_params(struct esp *esp)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
-       struct device_node *bus_dp;
+       struct of_device *op = esp->dev;
+       struct device_node *bus_dp, *dp;
        int fmhz;
 
-       bus_dp = NULL;
-       if (sdev != NULL && sdev->bus != NULL)
-               bus_dp = sdev->bus->ofdev.node;
+       dp = op->node;
+       bus_dp = dp->parent;
 
        fmhz = of_getintprop_default(dp, "clock-frequency", 0);
        if (fmhz == 0)
-               fmhz = (!bus_dp) ? 0 :
-                       of_getintprop_default(bus_dp, "clock-frequency", 0);
+               fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0);
 
        esp->cfreq = fmhz;
 }
 
-static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+static void __devinit esp_get_bursts(struct esp *esp, struct of_device *dma_of)
 {
-       struct sbus_dev *sdev = esp->dev;
-       struct device_node *dp = sdev->ofdev.node;
-       u8 bursts;
+       struct device_node *dma_dp = dma_of->node;
+       struct of_device *op = esp->dev;
+       struct device_node *dp;
+       u8 bursts, val;
 
+       dp = op->node;
        bursts = of_getintprop_default(dp, "burst-sizes", 0xff);
-       if (dma) {
-               struct device_node *dma_dp = dma->ofdev.node;
-               u8 val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
-               if (val != 0xff)
-                       bursts &= val;
-       }
+       val = of_getintprop_default(dma_dp, "burst-sizes", 0xff);
+       if (val != 0xff)
+               bursts &= val;
 
-       if (sdev->bus) {
-               u8 val = of_getintprop_default(sdev->bus->ofdev.node,
-                                              "burst-sizes", 0xff);
-               if (val != 0xff)
-                       bursts &= val;
-       }
+       val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff);
+       if (val != 0xff)
+               bursts &= val;
 
        if (bursts == 0xff ||
            (bursts & DMA_BURST16) == 0 ||
@@ -194,9 +194,9 @@ static void __devinit esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
        esp->bursts = bursts;
 }
 
-static void __devinit esp_sbus_get_props(struct esp *esp, struct sbus_dev *espdma)
+static void __devinit esp_sbus_get_props(struct esp *esp, struct of_device *espdma)
 {
-       esp_get_scsi_id(esp);
+       esp_get_scsi_id(esp, espdma);
        esp_get_differential(esp);
        esp_get_clock_params(esp);
        esp_get_bursts(esp, espdma);
@@ -215,25 +215,33 @@ static u8 sbus_esp_read8(struct esp *esp, unsigned long reg)
 static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf,
                                      size_t sz, int dir)
 {
-       return sbus_map_single(esp->dev, buf, sz, dir);
+       struct of_device *op = esp->dev;
+
+       return dma_map_single(&op->dev, buf, sz, dir);
 }
 
 static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg,
                                  int num_sg, int dir)
 {
-       return sbus_map_sg(esp->dev, sg, num_sg, dir);
+       struct of_device *op = esp->dev;
+
+       return dma_map_sg(&op->dev, sg, num_sg, dir);
 }
 
 static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr,
                                  size_t sz, int dir)
 {
-       sbus_unmap_single(esp->dev, addr, sz, dir);
+       struct of_device *op = esp->dev;
+
+       dma_unmap_single(&op->dev, addr, sz, dir);
 }
 
 static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
                              int num_sg, int dir)
 {
-       sbus_unmap_sg(esp->dev, sg, num_sg, dir);
+       struct of_device *op = esp->dev;
+
+       dma_unmap_sg(&op->dev, sg, num_sg, dir);
 }
 
 static int sbus_esp_irq_pending(struct esp *esp)
@@ -247,24 +255,26 @@ static void sbus_esp_reset_dma(struct esp *esp)
 {
        int can_do_burst16, can_do_burst32, can_do_burst64;
        int can_do_sbus64, lim;
+       struct of_device *op;
        u32 val;
 
        can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
        can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
        can_do_burst64 = 0;
        can_do_sbus64 = 0;
-       if (sbus_can_dma_64bit(esp->dev))
+       op = esp->dev;
+       if (sbus_can_dma_64bit())
                can_do_sbus64 = 1;
-       if (sbus_can_burst64(esp->sdev))
+       if (sbus_can_burst64())
                can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
 
        /* Put the DVMA into a known state. */
-       if (esp->dma->revision != dvmahme) {
+       if (esp->dmarev != dvmahme) {
                val = dma_read32(DMA_CSR);
                dma_write32(val | DMA_RST_SCSI, DMA_CSR);
                dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
        }
-       switch (esp->dma->revision) {
+       switch (esp->dmarev) {
        case dvmahme:
                dma_write32(DMA_RESET_FAS366, DMA_CSR);
                dma_write32(DMA_RST_SCSI, DMA_CSR);
@@ -282,7 +292,7 @@ static void sbus_esp_reset_dma(struct esp *esp)
 
                if (can_do_sbus64) {
                        esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
-                       sbus_set_sbus64(esp->dev, esp->bursts);
+                       sbus_set_sbus64(&op->dev, esp->bursts);
                }
 
                lim = 1000;
@@ -346,14 +356,14 @@ static void sbus_esp_dma_drain(struct esp *esp)
        u32 csr;
        int lim;
 
-       if (esp->dma->revision == dvmahme)
+       if (esp->dmarev == dvmahme)
                return;
 
        csr = dma_read32(DMA_CSR);
        if (!(csr & DMA_FIFO_ISDRAIN))
                return;
 
-       if (esp->dma->revision != dvmarev3 && esp->dma->revision != dvmaesc1)
+       if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1)
                dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR);
 
        lim = 1000;
@@ -369,7 +379,7 @@ static void sbus_esp_dma_drain(struct esp *esp)
 
 static void sbus_esp_dma_invalidate(struct esp *esp)
 {
-       if (esp->dma->revision == dvmahme) {
+       if (esp->dmarev == dvmahme) {
                dma_write32(DMA_RST_SCSI, DMA_CSR);
 
                esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
@@ -440,7 +450,7 @@ static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
                else
                        csr &= ~DMA_ST_WRITE;
                dma_write32(csr, DMA_CSR);
-               if (esp->dma->revision == dvmaesc1) {
+               if (esp->dmarev == dvmaesc1) {
                        u32 end = PAGE_ALIGN(addr + dma_count + 16U);
                        dma_write32(end - addr, DMA_COUNT);
                }
@@ -476,10 +486,8 @@ static const struct esp_driver_ops sbus_esp_ops = {
        .dma_error      =       sbus_esp_dma_error,
 };
 
-static int __devinit esp_sbus_probe_one(struct device *dev,
-                                       struct sbus_dev *esp_dev,
-                                       struct sbus_dev *espdma,
-                                       struct sbus_bus *sbus,
+static int __devinit esp_sbus_probe_one(struct of_device *op,
+                                       struct of_device *espdma,
                                        int hme)
 {
        struct scsi_host_template *tpnt = &scsi_esp_template;
@@ -497,13 +505,13 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
        esp = shost_priv(host);
 
        esp->host = host;
-       esp->dev = esp_dev;
+       esp->dev = op;
        esp->ops = &sbus_esp_ops;
 
        if (hme)
                esp->flags |= ESP_FLAG_WIDE_CAPABLE;
 
-       err = esp_sbus_find_dma(esp, espdma);
+       err = esp_sbus_setup_dma(esp, espdma);
        if (err < 0)
                goto fail_unlink;
 
@@ -525,15 +533,15 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
         * come up with the reset bit set, so make sure that
         * is clear first.
         */
-       if (esp->dma->revision == dvmaesc1) {
+       if (esp->dmarev == dvmaesc1) {
                u32 val = dma_read32(DMA_CSR);
 
                dma_write32(val & ~DMA_RST_SCSI, DMA_CSR);
        }
 
-       dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+       dev_set_drvdata(&op->dev, esp);
 
-       err = scsi_esp_register(esp, dev);
+       err = scsi_esp_register(esp, &op->dev);
        if (err)
                goto fail_free_irq;
 
@@ -542,41 +550,46 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
 fail_free_irq:
        free_irq(host->irq, esp);
 fail_unmap_command_block:
-       sbus_free_consistent(esp->dev, 16,
-                            esp->command_block,
-                            esp->command_block_dma);
+       dma_free_coherent(&op->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
 fail_unmap_regs:
-       sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+       of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE);
 fail_unlink:
        scsi_host_put(host);
 fail:
        return err;
 }
 
-static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit esp_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-       struct device_node *dp = dev->node;
-       struct sbus_dev *dma_sdev = NULL;
+       struct device_node *dma_node = NULL;
+       struct device_node *dp = op->node;
+       struct of_device *dma_of = NULL;
        int hme = 0;
 
        if (dp->parent &&
            (!strcmp(dp->parent->name, "espdma") ||
             !strcmp(dp->parent->name, "dma")))
-               dma_sdev = sdev->parent;
+               dma_node = dp->parent;
        else if (!strcmp(dp->name, "SUNW,fas")) {
-               dma_sdev = sdev;
+               dma_node = op->node;
                hme = 1;
        }
+       if (dma_node)
+               dma_of = of_find_device_by_node(dma_node);
+       if (!dma_of)
+               return -ENODEV;
 
-       return esp_sbus_probe_one(&dev->dev, sdev, dma_sdev,
-                                 sdev->bus, hme);
+       return esp_sbus_probe_one(op, dma_of, hme);
 }
 
-static int __devexit esp_sbus_remove(struct of_device *dev)
+static int __devexit esp_sbus_remove(struct of_device *op)
 {
-       struct esp *esp = dev_get_drvdata(&dev->dev);
+       struct esp *esp = dev_get_drvdata(&op->dev);
+       struct of_device *dma_of = esp->dma;
        unsigned int irq = esp->host->irq;
+       bool is_hme;
        u32 val;
 
        scsi_esp_unregister(esp);
@@ -586,17 +599,25 @@ static int __devexit esp_sbus_remove(struct of_device *dev)
        dma_write32(val & ~DMA_INT_ENAB, DMA_CSR);
 
        free_irq(irq, esp);
-       sbus_free_consistent(esp->dev, 16,
-                            esp->command_block,
-                            esp->command_block_dma);
-       sbus_iounmap(esp->regs, SBUS_ESP_REG_SIZE);
+
+       is_hme = (esp->dmarev == dvmahme);
+
+       dma_free_coherent(&op->dev, 16,
+                         esp->command_block,
+                         esp->command_block_dma);
+       of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs,
+                  SBUS_ESP_REG_SIZE);
+       of_iounmap(&dma_of->resource[0], esp->dma_regs,
+                  resource_size(&dma_of->resource[0]));
 
        scsi_host_put(esp->host);
 
+       dev_set_drvdata(&op->dev, NULL);
+
        return 0;
 }
 
-static struct of_device_id esp_match[] = {
+static const struct of_device_id esp_match[] = {
        {
                .name = "SUNW,esp",
        },
@@ -619,7 +640,7 @@ static struct of_platform_driver esp_sbus_driver = {
 
 static int __init sunesp_init(void)
 {
-       return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&esp_sbus_driver, &of_bus_type);
 }
 
 static void __exit sunesp_exit(void)
index e41766d08035643e18b72a2cfb88bf471355d885..a94a2ab4b5716cbb983d8d3d81e2d3e505dbc3e4 100644 (file)
@@ -616,7 +616,7 @@ static int __devexit hv_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id hv_match[] = {
+static const struct of_device_id hv_match[] = {
        {
                .name = "console",
                .compatible = "qcn",
index 29b4458abf744601f39a672bcb0333f5c92b519d..0355efe115d98d73f1f68842e6dd3364a73d28b7 100644 (file)
@@ -1078,7 +1078,7 @@ static int __devexit sab_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id sab_match[] = {
+static const struct of_device_id sab_match[] = {
        {
                .name = "se",
        },
index a378464f92927e83fde05e4e236eaa4f413f1aa5..a4dc79b1d7ab4b2d5f6df9e1a98a22c4d3d89fd9 100644 (file)
@@ -1506,7 +1506,7 @@ static int __devexit su_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id su_match[] = {
+static const struct of_device_id su_match[] = {
        {
                .name = "su",
        },
index 3cb4c8aee13fa74461648ff3a4ec9f12380fbba3..45a299f35617bc8eb27bd8b0fef9c6256f2cdbf0 100644 (file)
@@ -1480,7 +1480,7 @@ static int __devexit zs_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id zs_match[] = {
+static const struct of_device_id zs_match[] = {
        {
                .name = "zs",
        },
index 5799298364fb8dc1763f4530ca05ff99cec91b38..b697a13364ecee4d86d6c2dbbd7156001af961b8 100644 (file)
@@ -210,143 +210,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
-
-/* Section 2.2 Host Controller Capability Registers */
-struct ehci_caps {
-       /* these fields are specified as 8 and 16 bit registers,
-        * but some hosts can't perform 8 or 16 bit PCI accesses.
-        */
-       u32             hc_capbase;
-#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
-#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
-       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
-#define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
-#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_N_CC(p)            (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
-#define HCS_N_PCC(p)           (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p)      ((p)&(1 << 7))  /* true: port routing */
-#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
-#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
-
-       u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
-#define HCC_EXT_CAPS(p)                (((p)>>8)&0xff) /* for pci extended caps */
-#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
-#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
-#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
-#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
-       u8              portroute [8];   /* nibbles for routing - offset 0xC */
-} __attribute__ ((packed));
-
-
-/* Section 2.3 Host Controller Operational Registers */
-struct ehci_regs {
-
-       /* USBCMD: offset 0x00 */
-       u32             command;
-/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
-#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
-#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
-#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
-#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
-#define CMD_ASE                (1<<5)          /* async schedule enable */
-#define CMD_PSE                (1<<4)          /* periodic schedule enable */
-/* 3:2 is periodic frame list size */
-#define CMD_RESET      (1<<1)          /* reset HC not bus */
-#define CMD_RUN                (1<<0)          /* start/stop HC */
-
-       /* USBSTS: offset 0x04 */
-       u32             status;
-#define STS_ASS                (1<<15)         /* Async Schedule Status */
-#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
-#define STS_RECL       (1<<13)         /* Reclamation */
-#define STS_HALT       (1<<12)         /* Not running (any reason) */
-/* some bits reserved */
-       /* these STS_* flags are also intr_enable bits (USBINTR) */
-#define STS_IAA                (1<<5)          /* Interrupted on async advance */
-#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
-#define STS_FLR                (1<<3)          /* frame list rolled over */
-#define STS_PCD                (1<<2)          /* port change detect */
-#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
-#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
-
-       /* USBINTR: offset 0x08 */
-       u32             intr_enable;
-
-       /* FRINDEX: offset 0x0C */
-       u32             frame_index;    /* current microframe number */
-       /* CTRLDSSEGMENT: offset 0x10 */
-       u32             segment;        /* address bits 63:32 if needed */
-       /* PERIODICLISTBASE: offset 0x14 */
-       u32             frame_list;     /* points to periodic list */
-       /* ASYNCLISTADDR: offset 0x18 */
-       u32             async_next;     /* address of next async queue head */
-
-       u32             reserved [9];
-
-       /* CONFIGFLAG: offset 0x40 */
-       u32             configured_flag;
-#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
-
-       /* PORTSC: offset 0x44 */
-       u32             port_status [0];        /* up to N_PORTS */
-/* 31:23 reserved */
-#define PORT_WKOC_E    (1<<22)         /* wake on overcurrent (enable) */
-#define PORT_WKDISC_E  (1<<21)         /* wake on disconnect (enable) */
-#define PORT_WKCONN_E  (1<<20)         /* wake on connect (enable) */
-/* 19:16 for port testing */
-#define PORT_LED_OFF   (0<<14)
-#define PORT_LED_AMBER (1<<14)
-#define PORT_LED_GREEN (2<<14)
-#define PORT_LED_MASK  (3<<14)
-#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
-#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
-/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
-/* 9 reserved */
-#define PORT_RESET     (1<<8)          /* reset port */
-#define PORT_SUSPEND   (1<<7)          /* suspend port */
-#define PORT_RESUME    (1<<6)          /* resume it */
-#define PORT_OCC       (1<<5)          /* over current change */
-#define PORT_OC                (1<<4)          /* over current active */
-#define PORT_PEC       (1<<3)          /* port enable change */
-#define PORT_PE                (1<<2)          /* port enable */
-#define PORT_CSC       (1<<1)          /* connect status change */
-#define PORT_CONNECT   (1<<0)          /* device connected */
-#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
-} __attribute__ ((packed));
-
-#define USBMODE                0x68            /* USB Device mode */
-#define USBMODE_SDIS   (1<<3)          /* Stream disable */
-#define USBMODE_BE     (1<<2)          /* BE/LE endianness select */
-#define USBMODE_CM_HC  (3<<0)          /* host controller mode */
-#define USBMODE_CM_IDLE        (0<<0)          /* idle state */
-
-/* Appendix C, Debug port ... intended for use with special "debug devices"
- * that can help if there's no serial console.  (nonstandard enumeration.)
- */
-struct ehci_dbg_port {
-       u32     control;
-#define DBGP_OWNER     (1<<30)
-#define DBGP_ENABLED   (1<<28)
-#define DBGP_DONE      (1<<16)
-#define DBGP_INUSE     (1<<10)
-#define DBGP_ERRCODE(x)        (((x)>>7)&0x07)
-#      define DBGP_ERR_BAD     1
-#      define DBGP_ERR_SIGNAL  2
-#define DBGP_ERROR     (1<<6)
-#define DBGP_GO                (1<<5)
-#define DBGP_OUT       (1<<4)
-#define DBGP_LEN(x)    (((x)>>0)&0x0f)
-       u32     pids;
-#define DBGP_PID_GET(x)                (((x)>>16)&0xff)
-#define DBGP_PID_SET(data,tok) (((data)<<8)|(tok))
-       u32     data03;
-       u32     data47;
-       u32     address;
-#define DBGP_EPADDR(dev,ep)    (((dev)<<8)|(ep))
-} __attribute__ ((packed));
+#include <linux/usb/ehci_def.h>
 
 /*-------------------------------------------------------------------------*/
 
index d85a74c64b54e3cffb70b262e0f1f40524e4ff6d..f79c2040758b4ab43d867acaa451c1d2b3891934 100644 (file)
@@ -673,7 +673,6 @@ config FB_VESA
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
-       select VIDEO_SELECT
        help
          This is the frame buffer device driver for generic VESA 2.0
          compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -1578,7 +1577,6 @@ config FB_CYBLA
        tristate "Cyberblade/i1 support"
        depends on FB && PCI && X86_32 && !64BIT
        select FB_CFB_IMAGEBLIT
-       select VIDEO_SELECT
        ---help---
          This driver is supposed to support the Trident Cyberblade/i1
          graphics core integrated in the VIA VT8601A North Bridge,
index e721644bad743c27313b4d78db17b3f87a10de94..1e35ba6f18e01ef44eeda30e5685a9eb2f556317 100644 (file)
@@ -372,7 +372,7 @@ static int __devexit bw2_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id bw2_match[] = {
+static const struct of_device_id bw2_match[] = {
        {
                .name = "bwtwo",
        },
index b17e746717795615dc71a710abb801e9920eef7b..a2d1882791a58e11956b250afbca92fa520b9e79 100644 (file)
@@ -589,7 +589,7 @@ static int __devexit cg14_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg14_match[] = {
+static const struct of_device_id cg14_match[] = {
        {
                .name = "cgfourteen",
        },
index 3aa7b6cb0268591283b72f77425344be184d1420..99f87fb61d0558e816541fe0f133f79c2700decc 100644 (file)
@@ -456,7 +456,7 @@ static int __devexit cg3_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg3_match[] = {
+static const struct of_device_id cg3_match[] = {
        {
                .name = "cgthree",
        },
index 2f64bb3bd2540e7f5c77c03e7d5894578ddad572..940ec04f0f1be22665c99e548eaf9392a2fa13b1 100644 (file)
@@ -34,10 +34,11 @@ static int cg6_blank(int, struct fb_info *);
 
 static void cg6_imageblit(struct fb_info *, const struct fb_image *);
 static void cg6_fillrect(struct fb_info *, const struct fb_fillrect *);
+static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
 static int cg6_sync(struct fb_info *);
 static int cg6_mmap(struct fb_info *, struct vm_area_struct *);
 static int cg6_ioctl(struct fb_info *, unsigned int, unsigned long);
-static void cg6_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+static int cg6_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -47,6 +48,7 @@ static struct fb_ops cg6_ops = {
        .owner                  = THIS_MODULE,
        .fb_setcolreg           = cg6_setcolreg,
        .fb_blank               = cg6_blank,
+       .fb_pan_display         = cg6_pan_display,
        .fb_fillrect            = cg6_fillrect,
        .fb_copyarea            = cg6_copyarea,
        .fb_imageblit           = cg6_imageblit,
@@ -161,6 +163,7 @@ static struct fb_ops cg6_ops = {
 #define CG6_THC_MISC_INT_ENAB          (1 << 5)
 #define CG6_THC_MISC_INT               (1 << 4)
 #define CG6_THC_MISC_INIT              0x9f
+#define CG6_THC_CURSOFF                        ((65536-32) | ((65536-32) << 16))
 
 /* The contents are unknown */
 struct cg6_tec {
@@ -280,6 +283,33 @@ static int cg6_sync(struct fb_info *info)
        return 0;
 }
 
+static void cg6_switch_from_graph(struct cg6_par *par)
+{
+       struct cg6_thc __iomem *thc = par->thc;
+       unsigned long flags;
+
+       spin_lock_irqsave(&par->lock, flags);
+
+       /* Hide the cursor. */
+       sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
+       spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int cg6_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct cg6_par *par = (struct cg6_par *)info->par;
+
+       /* We just use this to catch switches out of
+        * graphics mode.
+        */
+       cg6_switch_from_graph(par);
+
+       if (var->xoffset || var->yoffset || var->vmode)
+               return -EINVAL;
+       return 0;
+}
+
 /**
  *     cg6_fillrect -  Draws a rectangle on the screen.
  *
@@ -643,9 +673,13 @@ static void __devinit cg6_chip_init(struct fb_info *info)
        struct cg6_par *par = (struct cg6_par *)info->par;
        struct cg6_tec __iomem *tec = par->tec;
        struct cg6_fbc __iomem *fbc = par->fbc;
+       struct cg6_thc __iomem *thc = par->thc;
        u32 rev, conf, mode;
        int i;
 
+       /* Hide the cursor. */
+       sbus_writel(CG6_THC_CURSOFF, &thc->thc_cursxy);
+
        /* Turn off stuff in the Transform Engine. */
        sbus_writel(0, &tec->tec_matrix);
        sbus_writel(0, &tec->tec_clip);
@@ -814,7 +848,7 @@ static int __devexit cg6_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id cg6_match[] = {
+static const struct of_device_id cg6_match[] = {
        {
                .name = "cgsix",
        },
index 06f87b04f207750074a5253cbf991df7405a9071..2f50a80b413e07910e64c49598284f9361810728 100644 (file)
@@ -43,22 +43,6 @@ config VGACON_SOFT_SCROLLBACK_SIZE
         buffer.  Each 64KB will give you approximately 16 80x25
         screenfuls of scrollback buffer
 
-config VIDEO_SELECT
-       bool "Video mode selection support"
-       depends on  X86 && VGA_CONSOLE
-       ---help---
-         This enables support for text mode selection on kernel startup. If
-         you want to take advantage of some high-resolution text mode your
-         card's BIOS offers, but the traditional Linux utilities like
-         SVGATextMode don't, you can say Y here and set the mode using the
-         "vga=" option from your boot loader (lilo or loadlin) or set
-         "vga=ask" which brings up a video mode menu on kernel startup. (Try
-         "man bootparam" or see the documentation of your boot loader about
-         how to pass options to the kernel.)
-
-         Read the file <file:Documentation/svga.txt> for more information
-         about the Video mode selection support. If unsure, say N.
-
 config MDA_CONSOLE
        depends on !M68K && !PARISC && ISA
        tristate "MDA text console (dual-headed) (EXPERIMENTAL)"
index 7992b13ee68fcac9a60840b0e17a9a3581e6713c..9dbb9646081f670a92c6c29733184a25c4ef107e 100644 (file)
@@ -1042,7 +1042,7 @@ static int __devexit ffb_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id ffb_match[] = {
+static const struct of_device_id ffb_match[] = {
        {
                .name = "SUNW,ffb",
        },
index 13fea61d6ae4cbf2bcdbca442eab84716e6e3499..7c7e8c2da9d911081f68d3b94d46f2effd69e496 100644 (file)
@@ -33,6 +33,7 @@ static int leo_blank(int, struct fb_info *);
 
 static int leo_mmap(struct fb_info *, struct vm_area_struct *);
 static int leo_ioctl(struct fb_info *, unsigned int, unsigned long);
+static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
  *  Frame buffer operations
@@ -42,6 +43,7 @@ static struct fb_ops leo_ops = {
        .owner                  = THIS_MODULE,
        .fb_setcolreg           = leo_setcolreg,
        .fb_blank               = leo_blank,
+       .fb_pan_display         = leo_pan_display,
        .fb_fillrect            = cfb_fillrect,
        .fb_copyarea            = cfb_copyarea,
        .fb_imageblit           = cfb_imageblit,
@@ -206,6 +208,60 @@ static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
        return;
 }
 
+static void leo_switch_from_graph(struct fb_info *info)
+{
+       struct leo_par *par = (struct leo_par *) info->par;
+       struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
+       struct leo_cursor __iomem *cursor = par->cursor;
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&par->lock, flags);
+
+       par->extent = ((info->var.xres - 1) |
+                      ((info->var.yres - 1) << 16));
+
+       sbus_writel(0xffffffff, &ss->wid);
+       sbus_writel(0xffff, &ss->wmask);
+       sbus_writel(0, &ss->vclipmin);
+       sbus_writel(par->extent, &ss->vclipmax);
+       sbus_writel(0, &ss->fg);
+       sbus_writel(0xff000000, &ss->planemask);
+       sbus_writel(0x310850, &ss->rop);
+       sbus_writel(0, &ss->widclip);
+       sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
+                   &par->lc_ss0_usr->extent);
+       sbus_writel(4, &par->lc_ss0_usr->addrspace);
+       sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
+       sbus_writel(0, &par->lc_ss0_usr->fontt);
+       do {
+               val = sbus_readl(&par->lc_ss0_usr->csr);
+       } while (val & 0x20000000);
+
+       /* setup screen buffer for cfb_* functions */
+       sbus_writel(1, &ss->wid);
+       sbus_writel(0x00ffffff, &ss->planemask);
+       sbus_writel(0x310b90, &ss->rop);
+       sbus_writel(0, &par->lc_ss0_usr->addrspace);
+
+       /* hide cursor */
+       sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc);
+
+       spin_unlock_irqrestore(&par->lock, flags);
+}
+
+static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       /* We just use this to catch switches out of
+        * graphics mode.
+        */
+       leo_switch_from_graph(info);
+
+       if (var->xoffset || var->yoffset || var->vmode)
+               return -EINVAL;
+       return 0;
+}
+
 /**
  *      leo_setcolreg - Optional function. Sets a color register.
  *      @regno: boolean, 0 copy local, 1 get_user() function
@@ -454,44 +510,6 @@ static void leo_init_wids(struct fb_info *info)
        leo_wid_put(info, &wl);
 }
 
-static void leo_switch_from_graph(struct fb_info *info)
-{
-       struct leo_par *par = (struct leo_par *) info->par;
-       struct leo_ld_ss0 __iomem *ss = par->ld_ss0;
-       unsigned long flags;
-       u32 val;
-
-       spin_lock_irqsave(&par->lock, flags);
-
-       par->extent = ((info->var.xres - 1) |
-                      ((info->var.yres - 1) << 16));
-
-       sbus_writel(0xffffffff, &ss->wid);
-       sbus_writel(0xffff, &ss->wmask);
-       sbus_writel(0, &ss->vclipmin);
-       sbus_writel(par->extent, &ss->vclipmax);
-       sbus_writel(0, &ss->fg);
-       sbus_writel(0xff000000, &ss->planemask);
-       sbus_writel(0x310850, &ss->rop);
-       sbus_writel(0, &ss->widclip);
-       sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11),
-                   &par->lc_ss0_usr->extent);
-       sbus_writel(4, &par->lc_ss0_usr->addrspace);
-       sbus_writel(0x80000000, &par->lc_ss0_usr->fill);
-       sbus_writel(0, &par->lc_ss0_usr->fontt);
-       do {
-               val = sbus_readl(&par->lc_ss0_usr->csr);
-       } while (val & 0x20000000);
-
-       /* setup screen buffer for cfb_* functions */
-       sbus_writel(1, &ss->wid);
-       sbus_writel(0x00ffffff, &ss->planemask);
-       sbus_writel(0x310b90, &ss->rop);
-       sbus_writel(0, &par->lc_ss0_usr->addrspace);
-
-       spin_unlock_irqrestore(&par->lock, flags);
-}
-
 static void leo_init_hw(struct fb_info *info)
 {
        struct leo_par *par = (struct leo_par *) info->par;
@@ -641,7 +659,7 @@ static int __devexit leo_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id leo_match[] = {
+static const struct of_device_id leo_match[] = {
        {
                .name = "SUNW,leo",
        },
index 9e903454ffc138b053c4ad32f7b12dd3636e8f94..7000f2cd58542e54668d58ecb3374e5c6c23d3fb 100644 (file)
@@ -349,7 +349,7 @@ static int __devexit p9100_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id p9100_match[] = {
+static const struct of_device_id p9100_match[] = {
        {
                .name = "p9100",
        },
index 2a03f78bbb0d53f60db6eaba3be24d09e31d4cdd..643afbfe8277bfe9bf03bf35a80c5d4a83e98841 100644 (file)
@@ -505,7 +505,7 @@ static int __devexit tcx_remove(struct of_device *op)
        return 0;
 }
 
-static struct of_device_id tcx_match[] = {
+static const struct of_device_id tcx_match[] = {
        {
                .name = "SUNW,tcx",
        },
index 47ed39b52f9c32162e5265404a5aacff9f9fbebe..a463b3dd837b5b9d6db40f68081fca7f89678e0f 100644 (file)
@@ -680,11 +680,11 @@ static struct xenbus_driver xenfb = {
 
 static int __init xenfb_init(void)
 {
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        /* Nothing to do if running in dom0. */
-       if (is_initial_xendomain())
+       if (xen_initial_domain())
                return -ENODEV;
 
        return xenbus_register_frontend(&xenfb);
index c510367167009a1e57e88826bf6bbfb453357b9b..1a22fe782a27b57205a3ce21dfa1c440d84b1835 100644 (file)
@@ -66,6 +66,13 @@ config AT91RM9200_WATCHDOG
          Watchdog timer embedded into AT91RM9200 chips. This will reboot your
          system when the timeout is reached.
 
+config AT91SAM9X_WATCHDOG
+       tristate "AT91SAM9X watchdog"
+       depends on WATCHDOG && (ARCH_AT91SAM9260 || ARCH_AT91SAM9261)
+       help
+         Watchdog timer embedded into AT91SAM9X chips. This will reboot your
+         system when the timeout is reached.
+
 config 21285_WATCHDOG
        tristate "DC21285 watchdog"
        depends on FOOTBRIDGE
@@ -217,6 +224,15 @@ config DAVINCI_WATCHDOG
          NOTE: once enabled, this timer cannot be disabled.
          Say N if you are unsure.
 
+config ORION5X_WATCHDOG
+       tristate "Orion5x watchdog"
+       depends on ARCH_ORION5X
+       help
+         Say Y here if to include support for the watchdog timer
+         in the Orion5x ARM SoCs.
+         To compile this driver as a module, choose M here: the
+         module will be called orion5x_wdt.
+
 # ARM26 Architecture
 
 # AVR32 Architecture
@@ -416,6 +432,18 @@ config IT8712F_WDT
          To compile this driver as a module, choose M here: the
          module will be called it8712f_wdt.
 
+config IT87_WDT
+       tristate "IT87 Watchdog Timer"
+       depends on X86 && EXPERIMENTAL
+       ---help---
+         This is the driver for the hardware watchdog on the ITE IT8716,
+         IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog
+         simply watches your kernel to make sure it doesn't freeze, and if
+         it does, it reboots your computer after a certain amount of time.
+
+         To compile this driver as a module, choose M here: the module will
+         be called it87_wdt.
+
 config HP_WATCHDOG
        tristate "HP Proliant iLO 2 Hardware Watchdog Timer"
        depends on X86
@@ -573,6 +601,21 @@ config W83697HF_WDT
 
          Most people will say N.
 
+config W83697UG_WDT
+       tristate "W83697UG/W83697UF Watchdog Timer"
+       depends on X86
+       ---help---
+         This is the driver for the hardware watchdog on the W83697UG/UF
+         chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
+         This watchdog simply watches your kernel to make sure it doesn't
+         freeze, and if it does, it reboots your computer after a certain
+         amount of time.
+
+         To compile this driver as a module, choose M here: the
+         module will be called w83697ug_wdt.
+
+         Most people will say N.
+
 config W83877F_WDT
        tristate "W83877F (EMACS) Watchdog Timer"
        depends on X86
index e0ef123fbdeaa859c08b64660f16fb1a407c8afb..e352bbb7630b405a0ac3dc30a03c88b2eaa4c6b9 100644 (file)
@@ -26,6 +26,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 
 # ARM Architecture
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
+obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
@@ -39,6 +40,7 @@ obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+obj-$(CONFIG_ORION5X_WATCHDOG) += orion5x_wdt.o
 
 # ARM26 Architecture
 
@@ -71,6 +73,7 @@ ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
 obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
 endif
 obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o
+obj-$(CONFIG_IT87_WDT) += it87_wdt.o
 obj-$(CONFIG_HP_WATCHDOG) += hpwdt.o
 obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
 obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -83,6 +86,7 @@ obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
 obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
 obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
+obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
@@ -123,6 +127,9 @@ obj-$(CONFIG_SH_WDT) += shwdt.o
 
 # SPARC64 Architecture
 
+obj-$(CONFIG_WATCHDOG_RIO)             += riowd.o
+obj-$(CONFIG_WATCHDOG_CP1XXX)          += cpwd.o
+
 # XTENSA Architecture
 
 # Architecture Independant
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
new file mode 100644 (file)
index 0000000..b4babfc
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Watchdog driver for Atmel AT91SAM9x processors.
+ *
+ * Copyright (C) 2008 Renaud CERRATO r.cerrato@til-technologies.fr
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The Watchdog Timer Mode Register can be only written to once. If the
+ * timeout need to be set from Linux, be sure that the bootstrap or the
+ * bootloader doesn't write to this register.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <linux/uaccess.h>
+
+#include <asm/arch/at91_wdt.h>
+
+#define DRV_NAME "AT91SAM9 Watchdog"
+
+/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
+ * use this to convert a watchdog
+ * value from/to milliseconds.
+ */
+#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
+#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+
+/* Hardware timeout in seconds */
+#define WDT_HW_TIMEOUT 2
+
+/* Timer heartbeat (500ms) */
+#define WDT_TIMEOUT    (HZ/2)
+
+/* User land timeout */
+#define WDT_HEARTBEAT 15
+static int heartbeat = WDT_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+       "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+       "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static void at91_ping(unsigned long data);
+
+static struct {
+       unsigned long next_heartbeat;   /* the next_heartbeat for the timer */
+       unsigned long open;
+       char expect_close;
+       struct timer_list timer;        /* The timer that pings the watchdog */
+} at91wdt_private;
+
+/* ......................................................................... */
+
+
+/*
+ * Reload the watchdog timer.  (ie, pat the watchdog)
+ */
+static inline void at91_wdt_reset(void)
+{
+       at91_sys_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+}
+
+/*
+ * Timer tick
+ */
+static void at91_ping(unsigned long data)
+{
+       if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
+                       (!nowayout && !at91wdt_private.open)) {
+               at91_wdt_reset();
+               mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+       } else
+               printk(KERN_CRIT DRV_NAME": I will reset your machine !\n");
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at91_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &at91wdt_private.open))
+               return -EBUSY;
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+       return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at91_wdt_close(struct inode *inode, struct file *file)
+{
+       clear_bit(0, &at91wdt_private.open);
+
+       /* stop internal ping */
+       if (!at91wdt_private.expect_close)
+               del_timer(&at91wdt_private.timer);
+
+       at91wdt_private.expect_close = 0;
+       return 0;
+}
+
+/*
+ * Set the watchdog time interval in 1/256Hz (write-once)
+ * Counter is 12 bit.
+ */
+static int at91_wdt_settimeout(unsigned int timeout)
+{
+       unsigned int reg;
+       unsigned int mr;
+
+       /* Check if disabled */
+       mr = at91_sys_read(AT91_WDT_MR);
+       if (mr & AT91_WDT_WDDIS) {
+               printk(KERN_ERR DRV_NAME": sorry, watchdog is disabled\n");
+               return -EIO;
+       }
+
+       /*
+        * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
+        *
+        * Since WDV is a 12-bit counter, the maximum period is
+        * 4096 / 256 = 16 seconds.
+        */
+       reg = AT91_WDT_WDRSTEN  /* causes watchdog reset */
+               /* | AT91_WDT_WDRPROC   causes processor reset only */
+               | AT91_WDT_WDDBGHLT     /* disabled in debug mode */
+               | AT91_WDT_WDD          /* restart at any time */
+               | (timeout & AT91_WDT_WDV);  /* timer value */
+       at91_sys_write(AT91_WDT_MR, reg);
+
+       return 0;
+}
+
+static const struct watchdog_info at91_wdt_info = {
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static long at91_wdt_ioctl(struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_value;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(argp, &at91_wdt_info,
+                                   sizeof(at91_wdt_info)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_KEEPALIVE:
+               at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+               return 0;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+
+               heartbeat = new_value;
+               at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+               return put_user(new_value, p);  /* return current value */
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(heartbeat, p);
+       }
+       return -ENOTTY;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
+      loff_t *ppos)
+{
+       if (!len)
+               return 0;
+
+       /* Scan for magic character */
+       if (!nowayout) {
+               size_t i;
+
+               at91wdt_private.expect_close = 0;
+
+               for (i = 0; i < len; i++) {
+                       char c;
+                       if (get_user(c, data + i))
+                               return -EFAULT;
+                       if (c == 'V') {
+                               at91wdt_private.expect_close = 42;
+                               break;
+                       }
+               }
+       }
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+
+       return len;
+}
+
+/* ......................................................................... */
+
+static const struct file_operations at91wdt_fops = {
+       .owner                  = THIS_MODULE,
+       .llseek                 = no_llseek,
+       .unlocked_ioctl = at91_wdt_ioctl,
+       .open                   = at91_wdt_open,
+       .release                = at91_wdt_close,
+       .write                  = at91_wdt_write,
+};
+
+static struct miscdevice at91wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &at91wdt_fops,
+};
+
+static int __init at91wdt_probe(struct platform_device *pdev)
+{
+       int res;
+
+       if (at91wdt_miscdev.parent)
+               return -EBUSY;
+       at91wdt_miscdev.parent = &pdev->dev;
+
+       /* Set watchdog */
+       res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
+       if (res)
+               return res;
+
+       res = misc_register(&at91wdt_miscdev);
+       if (res)
+               return res;
+
+       at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
+       setup_timer(&at91wdt_private.timer, at91_ping, 0);
+       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+
+       printk(KERN_INFO DRV_NAME " enabled (heartbeat=%d sec, nowayout=%d)\n",
+               heartbeat, nowayout);
+
+       return 0;
+}
+
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+       int res;
+
+       res = misc_deregister(&at91wdt_miscdev);
+       if (!res)
+               at91wdt_miscdev.parent = NULL;
+
+       return res;
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+       return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
+#else
+#define at91wdt_suspend        NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+       .remove         = __exit_p(at91wdt_remove),
+       .suspend        = at91wdt_suspend,
+       .resume         = at91wdt_resume,
+       .driver         = {
+               .name   = "at91_wdt",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init at91sam_wdt_init(void)
+{
+       return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
+}
+
+static void __exit at91sam_wdt_exit(void)
+{
+       platform_driver_unregister(&at91wdt_driver);
+}
+
+module_init(at91sam_wdt_init);
+module_exit(at91sam_wdt_exit);
+
+MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
new file mode 100644 (file)
index 0000000..084dfe9
--- /dev/null
@@ -0,0 +1,695 @@
+/* cpwd.c - driver implementation for hardware watchdog
+ * timers found on Sun Microsystems CP1400 and CP1500 boards.
+ *
+ * This device supports both the generic Linux watchdog 
+ * interface and Solaris-compatible ioctls as best it is
+ * able.
+ *
+ * NOTE:       CP1400 systems appear to have a defective intr_mask
+ *                     register on the PLD, preventing the disabling of
+ *                     timer interrupts.  We use a timer to periodically 
+ *                     reset 'stopped' watchdogs on affected platforms.
+ *
+ * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#define DRIVER_NAME    "cpwd"
+#define PFX            DRIVER_NAME ": "
+
+#define WD_OBPNAME     "watchdog"
+#define WD_BADMODEL    "SUNW,501-5336"
+#define WD_BTIMEOUT    (jiffies + (HZ * 1000))
+#define WD_BLIMIT      0xFFFF
+
+#define WD0_MINOR      212
+#define WD1_MINOR      213     
+#define WD2_MINOR      214     
+
+/* Internal driver definitions.  */
+#define WD0_ID                 0
+#define WD1_ID                 1
+#define WD2_ID                 2
+#define WD_NUMDEVS             3
+
+#define WD_INTR_OFF            0
+#define WD_INTR_ON             1
+
+#define WD_STAT_INIT   0x01    /* Watchdog timer is initialized        */
+#define WD_STAT_BSTOP  0x02    /* Watchdog timer is brokenstopped      */
+#define WD_STAT_SVCD   0x04    /* Watchdog interrupt occurred          */
+
+/* Register value definitions
+ */
+#define WD0_INTR_MASK  0x01    /* Watchdog device interrupt masks      */
+#define WD1_INTR_MASK  0x02
+#define WD2_INTR_MASK  0x04
+
+#define WD_S_RUNNING   0x01    /* Watchdog device status running       */
+#define WD_S_EXPIRED   0x02    /* Watchdog device status expired       */
+
+struct cpwd {
+       void __iomem    *regs;
+       spinlock_t      lock;
+
+       unsigned int    irq;
+
+       unsigned long   timeout;
+       bool            enabled;
+       bool            reboot;
+       bool            broken;
+       bool            initialized;
+
+       struct {
+               struct miscdevice       misc;
+               void __iomem            *regs;
+               u8                      intr_mask;
+               u8                      runstatus;
+               u16                     timeout;
+       } devs[WD_NUMDEVS];
+};
+
+static struct cpwd *cpwd_device;
+
+/* Sun uses Altera PLD EPF8820ATC144-4 
+ * providing three hardware watchdogs:
+ *
+ *     1) RIC - sends an interrupt when triggered
+ *     2) XIR - asserts XIR_B_RESET when triggered, resets CPU
+ *     3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
+ *
+ *** Timer register block definition (struct wd_timer_regblk)
+ *
+ * dcntr and limit registers (halfword access):      
+ * -------------------
+ * | 15 | ...| 1 | 0 |
+ * -------------------
+ * |-  counter val  -|
+ * -------------------
+ * dcntr -     Current 16-bit downcounter value.
+ *                     When downcounter reaches '0' watchdog expires.
+ *                     Reading this register resets downcounter with 'limit' value.
+ * limit -     16-bit countdown value in 1/10th second increments.
+ *                     Writing this register begins countdown with input value.
+ *                     Reading from this register does not affect counter.
+ * NOTES:      After watchdog reset, dcntr and limit contain '1'
+ *
+ * status register (byte access):
+ * ---------------------------
+ * | 7 | ... | 2 |  1  |  0  |
+ * --------------+------------
+ * |-   UNUSED  -| EXP | RUN |
+ * ---------------------------
+ * status-     Bit 0 - Watchdog is running
+ *                     Bit 1 - Watchdog has expired
+ *
+ *** PLD register block definition (struct wd_pld_regblk)
+ *
+ * intr_mask register (byte access):
+ * ---------------------------------
+ * | 7 | ... | 3 |  2  |  1  |  0  |
+ * +-------------+------------------
+ * |-   UNUSED  -| WD3 | WD2 | WD1 |
+ * ---------------------------------
+ * WD3 -  1 == Interrupt disabled for watchdog 3
+ * WD2 -  1 == Interrupt disabled for watchdog 2
+ * WD1 -  1 == Interrupt disabled for watchdog 1
+ *
+ * pld_status register (byte access):
+ * UNKNOWN, MAGICAL MYSTERY REGISTER
+ *
+ */
+#define WD_TIMER_REGSZ 16
+#define WD0_OFF                0
+#define WD1_OFF                (WD_TIMER_REGSZ * 1)
+#define WD2_OFF                (WD_TIMER_REGSZ * 2)
+#define PLD_OFF                (WD_TIMER_REGSZ * 3)
+
+#define WD_DCNTR       0x00
+#define WD_LIMIT       0x04
+#define WD_STATUS      0x08
+
+#define PLD_IMASK      (PLD_OFF + 0x00)
+#define PLD_STATUS     (PLD_OFF + 0x04)
+
+static struct timer_list cpwd_timer;
+
+static int wd0_timeout = 0;
+static int wd1_timeout = 0;
+static int wd2_timeout = 0;
+
+module_param   (wd0_timeout, int, 0);
+MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
+module_param   (wd1_timeout, int, 0);
+MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
+module_param   (wd2_timeout, int, 0);
+MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
+
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("watchdog");
+
+static void cpwd_writew(u16 val, void __iomem *addr)
+{
+       writew(cpu_to_le16(val), addr);
+}
+static u16 cpwd_readw(void __iomem *addr)
+{
+       u16 val = readw(addr);
+
+       return le16_to_cpu(val);
+}
+
+static void cpwd_writeb(u8 val, void __iomem *addr)
+{
+       writeb(val, addr);
+}
+
+static u8 cpwd_readb(void __iomem *addr)
+{
+       return readb(addr);
+}
+
+/* Enable or disable watchdog interrupts
+ * Because of the CP1400 defect this should only be
+ * called during initialzation or by wd_[start|stop]timer()
+ *
+ * index       - sub-device index, or -1 for 'all'
+ * enable      - non-zero to enable interrupts, zero to disable
+ */
+static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
+{
+       unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
+       unsigned char setregs = 
+               (index == -1) ? 
+               (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
+               (p->devs[index].intr_mask);
+
+       if (enable == WD_INTR_ON)
+               curregs &= ~setregs;
+       else
+               curregs |= setregs;
+
+       cpwd_writeb(curregs, p->regs + PLD_IMASK);
+}
+
+/* Restarts timer with maximum limit value and
+ * does not unset 'brokenstop' value.
+ */
+static void cpwd_resetbrokentimer(struct cpwd *p, int index)
+{
+       cpwd_toggleintr(p, index, WD_INTR_ON);
+       cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
+}
+
+/* Timer method called to reset stopped watchdogs--
+ * because of the PLD bug on CP1400, we cannot mask
+ * interrupts within the PLD so me must continually
+ * reset the timers ad infinitum.
+ */
+static void cpwd_brokentimer(unsigned long data)
+{
+       struct cpwd *p = (struct cpwd *) data;
+       int id, tripped = 0;
+
+       /* kill a running timer instance, in case we
+        * were called directly instead of by kernel timer
+        */
+       if (timer_pending(&cpwd_timer))
+               del_timer(&cpwd_timer);
+
+       for (id = 0; id < WD_NUMDEVS; id++) {
+               if (p->devs[id].runstatus & WD_STAT_BSTOP) {
+                       ++tripped;
+                       cpwd_resetbrokentimer(p, id);
+               }
+       }
+
+       if (tripped) {
+               /* there is at least one timer brokenstopped-- reschedule */
+               cpwd_timer.expires = WD_BTIMEOUT;
+               add_timer(&cpwd_timer);
+       }
+}
+
+/* Reset countdown timer with 'limit' value and continue countdown.
+ * This will not start a stopped timer.
+ */
+static void cpwd_pingtimer(struct cpwd *p, int index)
+{
+       if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
+               cpwd_readw(p->devs[index].regs + WD_DCNTR);
+}
+
+/* Stop a running watchdog timer-- the timer actually keeps
+ * running, but the interrupt is masked so that no action is
+ * taken upon expiration.
+ */
+static void cpwd_stoptimer(struct cpwd *p, int index)
+{
+       if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
+               cpwd_toggleintr(p, index, WD_INTR_OFF);
+
+               if (p->broken) {
+                       p->devs[index].runstatus |= WD_STAT_BSTOP;
+                       cpwd_brokentimer((unsigned long) p);
+               }
+       }
+}
+
+/* Start a watchdog timer with the specified limit value
+ * If the watchdog is running, it will be restarted with
+ * the provided limit value.
+ *
+ * This function will enable interrupts on the specified
+ * watchdog.
+ */
+static void cpwd_starttimer(struct cpwd *p, int index)
+{
+       if (p->broken)
+               p->devs[index].runstatus &= ~WD_STAT_BSTOP;
+
+       p->devs[index].runstatus &= ~WD_STAT_SVCD;
+
+       cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
+       cpwd_toggleintr(p, index, WD_INTR_ON);
+}
+
+static int cpwd_getstatus(struct cpwd *p, int index)
+{
+       unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
+       unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
+       unsigned char ret  = WD_STOPPED;
+
+       /* determine STOPPED */
+       if (!stat) 
+               return ret;
+
+       /* determine EXPIRED vs FREERUN vs RUNNING */
+       else if (WD_S_EXPIRED & stat) {
+               ret = WD_EXPIRED;
+       } else if(WD_S_RUNNING & stat) {
+               if (intr & p->devs[index].intr_mask) {
+                       ret = WD_FREERUN;
+               } else {
+                       /* Fudge WD_EXPIRED status for defective CP1400--
+                        * IF timer is running 
+                        *      AND brokenstop is set 
+                        *      AND an interrupt has been serviced
+                        * we are WD_EXPIRED.
+                        *
+                        * IF timer is running 
+                        *      AND brokenstop is set 
+                        *      AND no interrupt has been serviced
+                        * we are WD_FREERUN.
+                        */
+                       if (p->broken &&
+                           (p->devs[index].runstatus & WD_STAT_BSTOP)) {
+                               if (p->devs[index].runstatus & WD_STAT_SVCD) {
+                                       ret = WD_EXPIRED;
+                               } else {
+                                       /* we could as well pretend we are expired */
+                                       ret = WD_FREERUN;
+                               }
+                       } else {
+                               ret = WD_RUNNING;
+                       }
+               }
+       }
+
+       /* determine SERVICED */
+       if (p->devs[index].runstatus & WD_STAT_SVCD)
+               ret |= WD_SERVICED;
+
+       return(ret);
+}
+
+static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
+{
+       struct cpwd *p = dev_id;
+
+       /* Only WD0 will interrupt-- others are NMI and we won't
+        * see them here....
+        */
+       spin_lock_irq(&p->lock);
+
+       cpwd_stoptimer(p, WD0_ID);
+       p->devs[WD0_ID].runstatus |=  WD_STAT_SVCD;
+
+       spin_unlock_irq(&p->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int cpwd_open(struct inode *inode, struct file *f)
+{
+       struct cpwd *p = cpwd_device;
+
+       lock_kernel();
+       switch(iminor(inode)) {
+               case WD0_MINOR:
+               case WD1_MINOR:
+               case WD2_MINOR:
+                       break;
+
+               default:
+                       unlock_kernel();
+                       return -ENODEV;
+       }
+
+       /* Register IRQ on first open of device */
+       if (!p->initialized) {
+               if (request_irq(p->irq, &cpwd_interrupt, 
+                               IRQF_SHARED, DRIVER_NAME, p)) {
+                       printk(KERN_ERR PFX "Cannot register IRQ %d\n", 
+                               p->irq);
+                       unlock_kernel();
+                       return -EBUSY;
+               }
+               p->initialized = true;
+       }
+
+       unlock_kernel();
+
+       return nonseekable_open(inode, f);
+}
+
+static int cpwd_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static int cpwd_ioctl(struct inode *inode, struct file *file, 
+                     unsigned int cmd, unsigned long arg)
+{
+       static struct watchdog_info info = {
+               .options                = WDIOF_SETTIMEOUT,
+               .firmware_version       = 1,
+               .identity               = DRIVER_NAME,
+       };
+       void __user *argp = (void __user *)arg;
+       int index = iminor(inode) - WD0_MINOR;
+       struct cpwd *p = cpwd_device;
+       int setopt = 0;
+
+       switch (cmd) {
+       /* Generic Linux IOCTLs */
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               if (put_user(0, (int __user *)argp))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_KEEPALIVE:
+               cpwd_pingtimer(p, index);
+               break;
+
+       case WDIOC_SETOPTIONS:
+               if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
+                       return -EFAULT;
+
+               if (setopt & WDIOS_DISABLECARD) {
+                       if (p->enabled)
+                               return -EINVAL;
+                       cpwd_stoptimer(p, index);
+               } else if (setopt & WDIOS_ENABLECARD) {
+                       cpwd_starttimer(p, index);
+               } else {
+                       return -EINVAL;
+               }       
+               break;
+
+       /* Solaris-compatible IOCTLs */
+       case WIOCGSTAT:
+               setopt = cpwd_getstatus(p, index);
+               if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
+                       return -EFAULT;
+               break;
+
+       case WIOCSTART:
+               cpwd_starttimer(p, index);
+               break;
+
+       case WIOCSTOP:
+               if (p->enabled)
+                       return(-EINVAL);
+
+               cpwd_stoptimer(p, index);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
+                             unsigned long arg)
+{
+       int rval = -ENOIOCTLCMD;
+
+       switch (cmd) {
+       /* solaris ioctls are specific to this driver */
+       case WIOCSTART:
+       case WIOCSTOP:
+       case WIOCGSTAT:
+               lock_kernel();
+               rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+               unlock_kernel();
+               break;
+
+       /* everything else is handled by the generic compat layer */
+       default:
+               break;
+       }
+
+       return rval;
+}
+
+static ssize_t cpwd_write(struct file *file, const char __user *buf, 
+                         size_t count, loff_t *ppos)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct cpwd *p = cpwd_device;
+       int index = iminor(inode);
+
+       if (count) {
+               cpwd_pingtimer(p, index);
+               return 1;
+       }
+
+       return 0;
+}
+
+static ssize_t cpwd_read(struct file * file, char __user *buffer,
+                        size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+static const struct file_operations cpwd_fops = {
+       .owner =        THIS_MODULE,
+       .ioctl =        cpwd_ioctl,
+       .compat_ioctl = cpwd_compat_ioctl,
+       .open =         cpwd_open,
+       .write =        cpwd_write,
+       .read =         cpwd_read,
+       .release =      cpwd_release,
+};
+
+static int __devinit cpwd_probe(struct of_device *op,
+                               const struct of_device_id *match)
+{
+       struct device_node *options;
+       const char *str_prop;
+       const void *prop_val;
+       int i, err = -EINVAL;
+       struct cpwd *p;
+
+       if (cpwd_device)
+               return -EINVAL;
+
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       err = -ENOMEM;
+       if (!p) {
+               printk(KERN_ERR PFX "Unable to allocate struct cpwd.\n");
+               goto out;
+       }
+
+       p->irq = op->irqs[0];
+
+       spin_lock_init(&p->lock);
+
+       p->regs = of_ioremap(&op->resource[0], 0,
+                            4 * WD_TIMER_REGSZ, DRIVER_NAME);
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Unable to map registers.\n");
+               goto out_free;
+       }
+
+       options = of_find_node_by_path("/options");
+       err = -ENODEV;
+       if (!options) {
+               printk(KERN_ERR PFX "Unable to find /options node.\n");
+               goto out_iounmap;
+       }
+
+       prop_val = of_get_property(options, "watchdog-enable?", NULL);
+       p->enabled = (prop_val ? true : false);
+
+       prop_val = of_get_property(options, "watchdog-reboot?", NULL);
+       p->reboot = (prop_val ? true : false);
+
+       str_prop = of_get_property(options, "watchdog-timeout", NULL);
+       if (str_prop)
+               p->timeout = simple_strtoul(str_prop, NULL, 10);
+
+       /* CP1400s seem to have broken PLD implementations-- the
+        * interrupt_mask register cannot be written, so no timer
+        * interrupts can be masked within the PLD.
+        */
+       str_prop = of_get_property(op->node, "model", NULL);
+       p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
+
+       if (!p->enabled)
+               cpwd_toggleintr(p, -1, WD_INTR_OFF);
+
+       for (i = 0; i < WD_NUMDEVS; i++) {
+               static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
+               static int *parms[] = { &wd0_timeout,
+                                       &wd1_timeout,
+                                       &wd2_timeout };
+               struct miscdevice *mp = &p->devs[i].misc;
+
+               mp->minor = WD0_MINOR + i;
+               mp->name = cpwd_names[i];
+               mp->fops = &cpwd_fops;
+
+               p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
+               p->devs[i].intr_mask = (WD0_INTR_MASK << i);
+               p->devs[i].runstatus &= ~WD_STAT_BSTOP;
+               p->devs[i].runstatus |= WD_STAT_INIT;
+               p->devs[i].timeout = p->timeout;
+               if (*parms[i])
+                       p->devs[i].timeout = *parms[i];
+
+               err = misc_register(&p->devs[i].misc);
+               if (err) {
+                       printk(KERN_ERR "Could not register misc device for "
+                              "dev %d\n", i);
+                       goto out_unregister;
+               }
+       }
+
+       if (p->broken) {
+               init_timer(&cpwd_timer);
+               cpwd_timer.function     = cpwd_brokentimer;
+               cpwd_timer.data         = (unsigned long) p;
+               cpwd_timer.expires      = WD_BTIMEOUT;
+
+               printk(KERN_INFO PFX "PLD defect workaround enabled for "
+                      "model " WD_BADMODEL ".\n");
+       }
+
+       dev_set_drvdata(&op->dev, p);
+       cpwd_device = p;
+       err = 0;
+
+out:
+       return err;
+
+out_unregister:
+       for (i--; i >= 0; i--)
+               misc_deregister(&p->devs[i].misc);
+
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+
+out_free:
+       kfree(p);
+       goto out;
+}
+
+static int __devexit cpwd_remove(struct of_device *op)
+{
+       struct cpwd *p = dev_get_drvdata(&op->dev);
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               misc_deregister(&p->devs[i].misc);
+
+               if (!p->enabled) {
+                       cpwd_stoptimer(p, i);
+                       if (p->devs[i].runstatus & WD_STAT_BSTOP)
+                               cpwd_resetbrokentimer(p, i);
+               }
+       }
+
+       if (p->broken)
+               del_timer_sync(&cpwd_timer);
+
+       if (p->initialized)
+               free_irq(p->irq, p);
+
+       of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
+       kfree(p);
+
+       cpwd_device = NULL;
+
+       return 0;
+}
+
+static const struct of_device_id cpwd_match[] = {
+       {
+               .name = "watchdog",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, cpwd_match);
+
+static struct of_platform_driver cpwd_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = cpwd_match,
+       .probe          = cpwd_probe,
+       .remove         = __devexit_p(cpwd_remove),
+};
+
+static int __init cpwd_init(void)
+{
+       return of_register_driver(&cpwd_driver, &of_bus_type);
+}
+
+static void __exit cpwd_exit(void)
+{
+       of_unregister_driver(&cpwd_driver);
+}
+
+module_init(cpwd_init);
+module_exit(cpwd_exit);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
new file mode 100644 (file)
index 0000000..afb8af3
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ *     Watchdog Timer Driver
+ *        for ITE IT87xx Environment Control - Low Pin Count Input / Output
+ *
+ *     (c) Copyright 2007  Oliver Schuster <olivers137@aol.com>
+ *
+ *     Based on softdog.c      by Alan Cox,
+ *              83977f_wdt.c   by Jose Goncalves,
+ *              it87.c         by Chris Gauthron, Jean Delvare
+ *
+ *     Data-sheets: Publicly available at the ITE website
+ *                 http://www.ite.com.tw/
+ *
+ *     Support of the watchdog timers, which are available on
+ *     IT8716, IT8718, IT8726 and IT8712 (J,K version).
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_VERSION       "1.12"
+#define WATCHDOG_NAME          "IT87 WDT"
+#define PFX                    WATCHDOG_NAME ": "
+#define DRIVER_VERSION         WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
+#define WD_MAGIC               'V'
+
+/* Defaults for Module Parameter */
+#define DEFAULT_NOGAMEPORT     0
+#define DEFAULT_EXCLUSIVE      1
+#define DEFAULT_TIMEOUT        60
+#define DEFAULT_TESTMODE       0
+#define DEFAULT_NOWAYOUT       WATCHDOG_NOWAYOUT
+
+/* IO Ports */
+#define REG            0x2e
+#define VAL            0x2f
+
+/* Logical device Numbers LDN */
+#define GPIO           0x07
+#define GAMEPORT       0x09
+#define CIR            0x0a
+
+/* Configuration Registers and Functions */
+#define LDNREG         0x07
+#define CHIPID         0x20
+#define CHIPREV        0x22
+#define ACTREG         0x30
+#define BASEREG        0x60
+
+/* Chip Id numbers */
+#define NO_DEV_ID      0xffff
+#define IT8705_ID      0x8705
+#define IT8712_ID      0x8712
+#define IT8716_ID      0x8716
+#define IT8718_ID      0x8718
+#define IT8726_ID      0x8726  /* the data sheet suggest wrongly 0x8716 */
+
+/* GPIO Configuration Registers LDN=0x07 */
+#define WDTCTRL        0x71
+#define WDTCFG         0x72
+#define WDTVALLSB      0x73
+#define WDTVALMSB      0x74
+
+/* GPIO Bits WDTCTRL */
+#define WDT_CIRINT     0x80
+#define WDT_MOUSEINT   0x40
+#define WDT_KYBINT     0x20
+#define WDT_GAMEPORT   0x10 /* not it8718 */
+#define WDT_FORCE      0x02
+#define WDT_ZERO       0x01
+
+/* GPIO Bits WDTCFG */
+#define WDT_TOV1       0x80
+#define WDT_KRST       0x40
+#define WDT_TOVE       0x20
+#define WDT_PWROK      0x10
+#define WDT_INT_MASK   0x0f
+
+/* CIR Configuration Register LDN=0x0a */
+#define CIR_ILS        0x70
+
+/* The default Base address is not always available, we use this */
+#define CIR_BASE       0x0208
+
+/* CIR Controller */
+#define CIR_DR(b)      (b)
+#define CIR_IER(b)     (b + 1)
+#define CIR_RCR(b)     (b + 2)
+#define CIR_TCR1(b)    (b + 3)
+#define CIR_TCR2(b)    (b + 4)
+#define CIR_TSR(b)     (b + 5)
+#define CIR_RSR(b)     (b + 6)
+#define CIR_BDLR(b)    (b + 5)
+#define CIR_BDHR(b)    (b + 6)
+#define CIR_IIR(b)     (b + 7)
+
+/* Default Base address of Game port */
+#define GP_BASE_DEFAULT        0x0201
+
+/* wdt_status */
+#define WDTS_TIMER_RUN 0
+#define WDTS_DEV_OPEN  1
+#define WDTS_KEEPALIVE 2
+#define WDTS_LOCKED    3
+#define WDTS_USE_GP    4
+#define WDTS_EXPECTED  5
+
+static unsigned int base, gpact, ciract;
+static unsigned long wdt_status;
+static DEFINE_SPINLOCK(spinlock);
+
+static int nogameport = DEFAULT_NOGAMEPORT;
+static int exclusive  = DEFAULT_EXCLUSIVE;
+static int timeout    = DEFAULT_TIMEOUT;
+static int testmode   = DEFAULT_TESTMODE;
+static int nowayout   = DEFAULT_NOWAYOUT;
+
+module_param(nogameport, int, 0);
+MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default="
+               __MODULE_STRING(DEFAULT_NOGAMEPORT));
+module_param(exclusive, int, 0);
+MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default="
+               __MODULE_STRING(DEFAULT_EXCLUSIVE));
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="
+               __MODULE_STRING(DEFAULT_TIMEOUT));
+module_param(testmode, int, 0);
+MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="
+               __MODULE_STRING(DEFAULT_TESTMODE));
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT));
+
+/* Superio Chip */
+
+static inline void superio_enter(void)
+{
+       outb(0x87, REG);
+       outb(0x01, REG);
+       outb(0x55, REG);
+       outb(0x55, REG);
+}
+
+static inline void superio_exit(void)
+{
+       outb(0x02, REG);
+       outb(0x02, VAL);
+}
+
+static inline void superio_select(int ldn)
+{
+       outb(LDNREG, REG);
+       outb(ldn, VAL);
+}
+
+static inline int superio_inb(int reg)
+{
+       outb(reg, REG);
+       return inb(VAL);
+}
+
+static inline void superio_outb(int val, int reg)
+{
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+static inline int superio_inw(int reg)
+{
+       int val;
+       outb(reg++, REG);
+       val = inb(VAL) << 8;
+       outb(reg, REG);
+       val |= inb(VAL);
+       return val;
+}
+
+static inline void superio_outw(int val, int reg)
+{
+       outb(reg++, REG);
+       outb(val >> 8, VAL);
+       outb(reg, REG);
+       outb(val, VAL);
+}
+
+/* watchdog timer handling */
+
+static void wdt_keepalive(void)
+{
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               inb(base);
+       else
+               /* The timer reloads with around 5 msec delay */
+               outb(0x55, CIR_DR(base));
+       set_bit(WDTS_KEEPALIVE, &wdt_status);
+}
+
+static void wdt_start(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       if (test_bit(WDTS_USE_GP, &wdt_status))
+               superio_outb(WDT_GAMEPORT, WDTCTRL);
+       else
+               superio_outb(WDT_CIRINT, WDTCTRL);
+       if (!testmode)
+               superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG);
+       else
+               superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(timeout>>8, WDTVALMSB);
+       superio_outb(timeout, WDTVALLSB);
+
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+
+static void wdt_stop(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       superio_outb(0x00, WDTCTRL);
+       superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(0x00, WDTVALMSB);
+       superio_outb(0x00, WDTVALLSB);
+
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+}
+
+/**
+ *     wdt_set_timeout - set a new timeout value with watchdog ioctl
+ *     @t: timeout value in seconds
+ *
+ *     The hardware device has a 16 bit watchdog timer, thus the
+ *     timeout time ranges between 1 and 65535 seconds.
+ *
+ *     Used within WDIOC_SETTIMEOUT watchdog device ioctl.
+ */
+
+static int wdt_set_timeout(int t)
+{
+       unsigned long flags;
+
+       if (t < 1 || t > 65535)
+               return -EINVAL;
+
+       timeout = t;
+
+       spin_lock_irqsave(&spinlock, flags);
+       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               superio_enter();
+
+               superio_select(GPIO);
+               superio_outb(t>>8, WDTVALMSB);
+               superio_outb(t, WDTVALLSB);
+
+               superio_exit();
+       }
+       spin_unlock_irqrestore(&spinlock, flags);
+       return 0;
+}
+
+/**
+ *     wdt_get_status - determines the status supported by watchdog ioctl
+ *     @status: status returned to user space
+ *
+ *     The status bit of the device does not allow to distinguish
+ *     between a regular system reset and a watchdog forced reset.
+ *     But, in test mode it is useful, so it is supported through
+ *     WDIOC_GETSTATUS watchdog ioctl. Additionally the driver
+ *     reports the keepalive signal and the acception of the magic.
+ *
+ *     Used within WDIOC_GETSTATUS watchdog device ioctl.
+ */
+
+static int wdt_get_status(int *status)
+{
+       unsigned long flags;
+
+       *status = 0;
+       if (testmode) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(GPIO);
+               if (superio_inb(WDTCTRL) & WDT_ZERO) {
+                       superio_outb(0x00, WDTCTRL);
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       *status |= WDIOF_CARDRESET;
+               }
+
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+       if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
+               *status |= WDIOF_KEEPALIVEPING;
+       if (test_bit(WDTS_EXPECTED, &wdt_status))
+               *status |= WDIOF_MAGICCLOSE;
+       return 0;
+}
+
+/* /dev/watchdog handling */
+
+/**
+ *     wdt_open - watchdog file_operations .open
+ *     @inode: inode of the device
+ *     @file: file handle to the device
+ *
+ *     The watchdog timer starts by opening the device.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
+               return -EBUSY;
+       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
+                       __module_get(THIS_MODULE);
+               wdt_start();
+       }
+       return nonseekable_open(inode, file);
+}
+
+/**
+ *     wdt_release - watchdog file_operations .release
+ *     @inode: inode of the device
+ *     @file: file handle to the device
+ *
+ *     Closing the watchdog device either stops the watchdog timer
+ *     or in the case, that nowayout is set or the magic character
+ *     wasn't written, a critical warning about an running watchdog
+ *     timer is given.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static int wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
+               if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
+                       wdt_stop();
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+               } else {
+                       wdt_keepalive();
+                       printk(KERN_CRIT PFX
+                              "unexpected close, not stopping watchdog!\n");
+               }
+       }
+       clear_bit(WDTS_DEV_OPEN, &wdt_status);
+       return 0;
+}
+
+/**
+ *     wdt_write - watchdog file_operations .write
+ *     @file: file handle to the watchdog
+ *     @buf: buffer to write
+ *     @count: count of bytes
+ *     @ppos: pointer to the position to write. No seeks allowed
+ *
+ *     A write to a watchdog device is defined as a keepalive signal. Any
+ *     write of data will do, as we don't define content meaning.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       if (count) {
+               clear_bit(WDTS_EXPECTED, &wdt_status);
+               wdt_keepalive();
+       }
+       if (!nowayout) {
+               size_t ofs;
+
+       /* note: just in case someone wrote the magic character long ago */
+               for (ofs = 0; ofs != count; ofs++) {
+                       char c;
+                       if (get_user(c, buf + ofs))
+                               return -EFAULT;
+                       if (c == WD_MAGIC)
+                               set_bit(WDTS_EXPECTED, &wdt_status);
+               }
+       }
+       return count;
+}
+
+static struct watchdog_info ident = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+       .firmware_version =     1,
+       .identity = WATCHDOG_NAME,
+};
+
+/**
+ *     wdt_ioctl - watchdog file_operations .unlocked_ioctl
+ *     @file: file handle to the device
+ *     @cmd: watchdog command
+ *     @arg: argument pointer
+ *
+ *     The watchdog API defines a common set of functions for all watchdogs
+ *     according to their available features.
+ *
+ *     Used within the file operation of the watchdog device.
+ */
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       int rc = 0, status, new_options, new_timeout;
+       union {
+               struct watchdog_info __user *ident;
+               int __user *i;
+       } uarg;
+
+       uarg.i = (int __user *)arg;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               return copy_to_user(uarg.ident,
+                                   &ident, sizeof(ident)) ? -EFAULT : 0;
+
+       case WDIOC_GETSTATUS:
+               wdt_get_status(&status);
+               return put_user(status, uarg.i);
+
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, uarg.i);
+
+       case WDIOC_KEEPALIVE:
+               wdt_keepalive();
+               return 0;
+
+       case WDIOC_SETOPTIONS:
+               if (get_user(new_options, uarg.i))
+                       return -EFAULT;
+
+               switch (new_options) {
+               case WDIOS_DISABLECARD:
+                       if (test_bit(WDTS_TIMER_RUN, &wdt_status))
+                               wdt_stop();
+                       clear_bit(WDTS_TIMER_RUN, &wdt_status);
+                       return 0;
+
+               case WDIOS_ENABLECARD:
+                       if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status))
+                               wdt_start();
+                       return 0;
+
+               default:
+                       return -EFAULT;
+               }
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, uarg.i))
+                       return -EFAULT;
+               rc = wdt_set_timeout(new_timeout);
+       case WDIOC_GETTIMEOUT:
+               if (put_user(timeout, uarg.i))
+                       return -EFAULT;
+               return rc;
+
+       default:
+               return -ENOTTY;
+       }
+}
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               wdt_stop();
+       return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = wdt_write,
+       .unlocked_ioctl = wdt_ioctl,
+       .open           = wdt_open,
+       .release        = wdt_release,
+};
+
+static struct miscdevice wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &wdt_fops,
+};
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
+static int __init it87_wdt_init(void)
+{
+       int rc = 0;
+       u16 chip_type;
+       u8  chip_rev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+       chip_type = superio_inw(CHIPID);
+       chip_rev  = superio_inb(CHIPREV) & 0x0f;
+       superio_exit();
+       spin_unlock_irqrestore(&spinlock, flags);
+
+       switch (chip_type) {
+       case IT8716_ID:
+       case IT8718_ID:
+       case IT8726_ID:
+               break;
+       case IT8712_ID:
+               if (chip_rev > 7)
+                       break;
+       case IT8705_ID:
+               printk(KERN_ERR PFX
+                      "Unsupported Chip found, Chip %04x Revision %02x\n",
+                      chip_type, chip_rev);
+               return -ENODEV;
+       case NO_DEV_ID:
+               printk(KERN_ERR PFX "no device\n");
+               return -ENODEV;
+       default:
+               printk(KERN_ERR PFX
+                      "Unknown Chip found, Chip %04x Revision %04x\n",
+                      chip_type, chip_rev);
+               return -ENODEV;
+       }
+
+       spin_lock_irqsave(&spinlock, flags);
+       superio_enter();
+
+       superio_select(GPIO);
+       superio_outb(WDT_TOV1, WDTCFG);
+       superio_outb(0x00, WDTCTRL);
+
+       /* First try to get Gameport support */
+       if (chip_type != IT8718_ID && !nogameport) {
+               superio_select(GAMEPORT);
+               base = superio_inw(BASEREG);
+               if (!base) {
+                       base = GP_BASE_DEFAULT;
+                       superio_outw(base, BASEREG);
+               }
+               gpact = superio_inb(ACTREG);
+               superio_outb(0x01, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+               if (request_region(base, 1, WATCHDOG_NAME))
+                       set_bit(WDTS_USE_GP, &wdt_status);
+               else
+                       rc = -EIO;
+       } else {
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       /* If we haven't Gameport support, try to get CIR support */
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
+                       if (rc == -EIO)
+                               printk(KERN_ERR PFX
+                                       "I/O Address 0x%04x and 0x%04x"
+                                       " already in use\n", base, CIR_BASE);
+                       else
+                               printk(KERN_ERR PFX
+                                       "I/O Address 0x%04x already in use\n",
+                                       CIR_BASE);
+                       rc = -EIO;
+                       goto err_out;
+               }
+               base = CIR_BASE;
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+
+               superio_select(CIR);
+               superio_outw(base, BASEREG);
+               superio_outb(0x00, CIR_ILS);
+               ciract = superio_inb(ACTREG);
+               superio_outb(0x01, ACTREG);
+               if (rc == -EIO) {
+                       superio_select(GAMEPORT);
+                       superio_outb(gpact, ACTREG);
+               }
+
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       if (timeout < 1 || timeout > 65535) {
+               timeout = DEFAULT_TIMEOUT;
+               printk(KERN_WARNING PFX
+                      "Timeout value out of range, use default %d sec\n",
+                      DEFAULT_TIMEOUT);
+       }
+
+       rc = register_reboot_notifier(&wdt_notifier);
+       if (rc) {
+               printk(KERN_ERR PFX
+                      "Cannot register reboot notifier (err=%d)\n", rc);
+               goto err_out_region;
+       }
+
+       rc = misc_register(&wdt_miscdev);
+       if (rc) {
+               printk(KERN_ERR PFX
+                      "Cannot register miscdev on minor=%d (err=%d)\n",
+                       wdt_miscdev.minor, rc);
+               goto err_out_reboot;
+       }
+
+       /* Initialize CIR to use it as keepalive source */
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               outb(0x00, CIR_RCR(base));
+               outb(0xc0, CIR_TCR1(base));
+               outb(0x5c, CIR_TCR2(base));
+               outb(0x10, CIR_IER(base));
+               outb(0x00, CIR_BDHR(base));
+               outb(0x01, CIR_BDLR(base));
+               outb(0x09, CIR_IER(base));
+       }
+
+       printk(KERN_INFO PFX "Chip it%04x revision %d initialized. "
+               "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d "
+               "nogameport=%d)\n", chip_type, chip_rev, timeout,
+               nowayout, testmode, exclusive, nogameport);
+
+       return 0;
+
+err_out_reboot:
+       unregister_reboot_notifier(&wdt_notifier);
+err_out_region:
+       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+       if (!test_bit(WDTS_USE_GP, &wdt_status)) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(CIR);
+               superio_outb(ciract, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+err_out:
+       if (chip_type != IT8718_ID && !nogameport) {
+               spin_lock_irqsave(&spinlock, flags);
+               superio_enter();
+               superio_select(GAMEPORT);
+               superio_outb(gpact, ACTREG);
+               superio_exit();
+               spin_unlock_irqrestore(&spinlock, flags);
+       }
+
+       return rc;
+}
+
+static void __exit it87_wdt_exit(void)
+{
+       unsigned long flags;
+       int nolock;
+
+       nolock = !spin_trylock_irqsave(&spinlock, flags);
+       superio_enter();
+       superio_select(GPIO);
+       superio_outb(0x00, WDTCTRL);
+       superio_outb(0x00, WDTCFG);
+       superio_outb(0x00, WDTVALMSB);
+       superio_outb(0x00, WDTVALLSB);
+       if (test_bit(WDTS_USE_GP, &wdt_status)) {
+               superio_select(GAMEPORT);
+               superio_outb(gpact, ACTREG);
+       } else {
+               superio_select(CIR);
+               superio_outb(ciract, ACTREG);
+       }
+       superio_exit();
+       if (!nolock)
+               spin_unlock_irqrestore(&spinlock, flags);
+
+       misc_deregister(&wdt_miscdev);
+       unregister_reboot_notifier(&wdt_notifier);
+       release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
+}
+
+module_init(it87_wdt_init);
+module_exit(it87_wdt_exit);
+
+MODULE_AUTHOR("Oliver Schuster");
+MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 3a11dadfd8e7dba34103f9d9b8685648e14a6f31..7bcbb7f4745f622758d68e2b36188d94c0668da8 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * linux/drivers/char/watchdog/omap_wdt.c
+ * omap_wdt.c
  *
- * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ * Watchdog driver for the TI OMAP 16xx & 24xx/34xx 32KHz (non-secure) watchdog
  *
  * Author: MontaVista Software, Inc.
  *      <gdavis@mvista.com> or <source@mvista.com>
 
 #include "omap_wdt.h"
 
+static struct platform_device *omap_wdt_dev;
+
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static int omap_wdt_users;
-static struct clk *armwdt_ck;
-static struct clk *mpu_wdt_ick;
-static struct clk *mpu_wdt_fck;
-
 static unsigned int wdt_trgr_pattern = 0x1234;
 static spinlock_t wdt_lock;
 
-static void omap_wdt_ping(void)
+struct omap_wdt_dev {
+       void __iomem    *base;          /* physical */
+       struct device   *dev;
+       int             omap_wdt_users;
+       struct clk      *armwdt_ck;
+       struct clk      *mpu_wdt_ick;
+       struct clk      *mpu_wdt_fck;
+       struct resource *mem;
+       struct miscdevice omap_wdt_miscdev;
+};
+
+static void omap_wdt_ping(struct omap_wdt_dev *wdev)
 {
+       void __iomem    *base = wdev->base;
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
+
        wdt_trgr_pattern = ~wdt_trgr_pattern;
-       omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+
        /* wait for posted write to complete */
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
        /* reloaded WCRR from WLDR */
 }
 
-static void omap_wdt_enable(void)
+static void omap_wdt_enable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* Sequence to enable the watchdog */
-       omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+       __raw_writel(0xBBBB, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
-       omap_writel(0x4444, OMAP_WATCHDOG_SPR);
-       while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+
+       __raw_writel(0x4444, base + OMAP_WATCHDOG_SPR);
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x10)
                cpu_relax();
 }
 
-static void omap_wdt_disable(void)
+static void omap_wdt_disable(struct omap_wdt_dev *wdev)
 {
+       void __iomem *base = wdev->base;
+
        /* sequence required to disable watchdog */
-       omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+       __raw_writel(0xAAAA, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
-       omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+
+       __raw_writel(0x5555, base + OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x10)
                cpu_relax();
 }
 
@@ -103,83 +121,90 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
        timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(void)
+static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
 {
        u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
-       omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+
+       __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 }
 
 /*
  *     Allow only one task to hold it open
  */
-
 static int omap_wdt_open(struct inode *inode, struct file *file)
 {
-       if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       void __iomem *base = wdev->base;
+
+       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
                return -EBUSY;
 
        if (cpu_is_omap16xx())
-               clk_enable(armwdt_ck);  /* Enable the clock */
+               clk_enable(wdev->armwdt_ck);    /* Enable the clock */
 
-       if (cpu_is_omap24xx()) {
-               clk_enable(mpu_wdt_ick);    /* Enable the interface clock */
-               clk_enable(mpu_wdt_fck);    /* Enable the functional clock */
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_enable(wdev->mpu_wdt_ick);    /* Enable the interface clock */
+               clk_enable(wdev->mpu_wdt_fck);    /* Enable the functional clock */
        }
 
        /* initialize prescaler */
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
-       omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
-       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+
+       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       omap_wdt_set_timeout();
-       omap_wdt_enable();
+       file->private_data = (void *) wdev;
+
+       omap_wdt_set_timeout(wdev);
+       omap_wdt_enable(wdev);
+
        return nonseekable_open(inode, file);
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /*
         *      Shut off the timer unless NOWAYOUT is defined.
         */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
-       omap_wdt_disable();
 
-       if (cpu_is_omap16xx()) {
-               clk_disable(armwdt_ck); /* Disable the clock */
-               clk_put(armwdt_ck);
-               armwdt_ck = NULL;
-       }
+       omap_wdt_disable(wdev);
 
-       if (cpu_is_omap24xx()) {
-               clk_disable(mpu_wdt_ick);       /* Disable the clock */
-               clk_disable(mpu_wdt_fck);       /* Disable the clock */
-               clk_put(mpu_wdt_ick);
-               clk_put(mpu_wdt_fck);
-               mpu_wdt_ick = NULL;
-               mpu_wdt_fck = NULL;
+       if (cpu_is_omap16xx())
+               clk_disable(wdev->armwdt_ck);   /* Disable the clock */
+
+       if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+               clk_disable(wdev->mpu_wdt_ick); /* Disable the clock */
+               clk_disable(wdev->mpu_wdt_fck); /* Disable the clock */
        }
 #else
        printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
 #endif
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+
        return 0;
 }
 
 static ssize_t omap_wdt_write(struct file *file, const char __user *data,
                size_t len, loff_t *ppos)
 {
+       struct omap_wdt_dev *wdev = file->private_data;
+
        /* Refresh LOAD_TIME. */
        if (len) {
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
        }
        return len;
@@ -188,6 +213,7 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
 static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                                                unsigned long arg)
 {
+       struct omap_wdt_dev *wdev;
        int new_margin;
        static const struct watchdog_info ident = {
                .identity = "OMAP Watchdog",
@@ -195,6 +221,8 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                .firmware_version = 0,
        };
 
+       wdev = file->private_data;
+
        switch (cmd) {
        case WDIOC_GETSUPPORT:
                return copy_to_user((struct watchdog_info __user *)arg, &ident,
@@ -203,14 +231,14 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                return put_user(0, (int __user *)arg);
        case WDIOC_GETBOOTSTATUS:
                if (cpu_is_omap16xx())
-                       return put_user(omap_readw(ARM_SYSST),
+                       return put_user(__raw_readw(ARM_SYSST),
                                        (int __user *)arg);
                if (cpu_is_omap24xx())
                        return put_user(omap_prcm_get_reset_sources(),
                                        (int __user *)arg);
        case WDIOC_KEEPALIVE:
                spin_lock(&wdt_lock);
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                return 0;
        case WDIOC_SETTIMEOUT:
@@ -219,11 +247,11 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
                omap_wdt_adjust_timeout(new_margin);
 
                spin_lock(&wdt_lock);
-               omap_wdt_disable();
-               omap_wdt_set_timeout();
-               omap_wdt_enable();
+               omap_wdt_disable(wdev);
+               omap_wdt_set_timeout(wdev);
+               omap_wdt_enable(wdev);
 
-               omap_wdt_ping();
+               omap_wdt_ping(wdev);
                spin_unlock(&wdt_lock);
                /* Fall */
        case WDIOC_GETTIMEOUT:
@@ -241,96 +269,173 @@ static const struct file_operations omap_wdt_fops = {
        .release = omap_wdt_release,
 };
 
-static struct miscdevice omap_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &omap_wdt_fops,
-};
-
 static int __init omap_wdt_probe(struct platform_device *pdev)
 {
        struct resource *res, *mem;
+       struct omap_wdt_dev *wdev;
        int ret;
 
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
+       if (!res) {
+               ret = -ENOENT;
+               goto err_get_resource;
+       }
+
+       if (omap_wdt_dev) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
        mem = request_mem_region(res->start, res->end - res->start + 1,
                                 pdev->name);
-       if (mem == NULL)
-               return -EBUSY;
+       if (!mem) {
+               ret = -EBUSY;
+               goto err_busy;
+       }
 
-       platform_set_drvdata(pdev, mem);
+       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
+       if (!wdev) {
+               ret = -ENOMEM;
+               goto err_kzalloc;
+       }
 
-       omap_wdt_users = 0;
+       wdev->omap_wdt_users = 0;
+       wdev->mem = mem;
 
        if (cpu_is_omap16xx()) {
-               armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
-               if (IS_ERR(armwdt_ck)) {
-                       ret = PTR_ERR(armwdt_ck);
-                       armwdt_ck = NULL;
-                       goto fail;
+               wdev->armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+               if (IS_ERR(wdev->armwdt_ck)) {
+                       ret = PTR_ERR(wdev->armwdt_ck);
+                       wdev->armwdt_ck = NULL;
+                       goto err_clk;
                }
        }
 
        if (cpu_is_omap24xx()) {
-               mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
-               if (IS_ERR(mpu_wdt_ick)) {
-                       ret = PTR_ERR(mpu_wdt_ick);
-                       mpu_wdt_ick = NULL;
-                       goto fail;
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
                }
-               mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
-               if (IS_ERR(mpu_wdt_fck)) {
-                       ret = PTR_ERR(mpu_wdt_fck);
-                       mpu_wdt_fck = NULL;
-                       goto fail;
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
                }
        }
 
-       omap_wdt_disable();
+       if (cpu_is_omap34xx()) {
+               wdev->mpu_wdt_ick = clk_get(&pdev->dev, "wdt2_ick");
+               if (IS_ERR(wdev->mpu_wdt_ick)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_ick);
+                       wdev->mpu_wdt_ick = NULL;
+                       goto err_clk;
+               }
+               wdev->mpu_wdt_fck = clk_get(&pdev->dev, "wdt2_fck");
+               if (IS_ERR(wdev->mpu_wdt_fck)) {
+                       ret = PTR_ERR(wdev->mpu_wdt_fck);
+                       wdev->mpu_wdt_fck = NULL;
+                       goto err_clk;
+               }
+       }
+       wdev->base = ioremap(res->start, res->end - res->start + 1);
+       if (!wdev->base) {
+               ret = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       platform_set_drvdata(pdev, wdev);
+
+       omap_wdt_disable(wdev);
        omap_wdt_adjust_timeout(timer_margin);
 
-       omap_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&omap_wdt_miscdev);
+       wdev->omap_wdt_miscdev.parent = &pdev->dev;
+       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
+       wdev->omap_wdt_miscdev.name = "watchdog";
+       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+
+       ret = misc_register(&(wdev->omap_wdt_miscdev));
        if (ret)
-               goto fail;
+               goto err_misc;
 
-       pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+       pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
+               __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
+               timer_margin);
 
        /* autogate OCP interface clock */
-       omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+       __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
+
+       omap_wdt_dev = pdev;
+
        return 0;
 
-fail:
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
-       release_resource(mem);
+err_misc:
+       platform_set_drvdata(pdev, NULL);
+       iounmap(wdev->base);
+
+err_ioremap:
+       wdev->base = NULL;
+
+err_clk:
+       if (wdev->armwdt_ck)
+               clk_put(wdev->armwdt_ck);
+       if (wdev->mpu_wdt_ick)
+               clk_put(wdev->mpu_wdt_ick);
+       if (wdev->mpu_wdt_fck)
+               clk_put(wdev->mpu_wdt_fck);
+       kfree(wdev);
+
+err_kzalloc:
+       release_mem_region(res->start, res->end - res->start + 1);
+
+err_busy:
+err_get_resource:
+
        return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct resource *mem = platform_get_drvdata(pdev);
-       misc_deregister(&omap_wdt_miscdev);
-       release_resource(mem);
-       if (armwdt_ck)
-               clk_put(armwdt_ck);
-       if (mpu_wdt_ick)
-               clk_put(mpu_wdt_ick);
-       if (mpu_wdt_fck)
-               clk_put(mpu_wdt_fck);
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       if (!res)
+               return -ENOENT;
+
+       misc_deregister(&(wdev->omap_wdt_miscdev));
+       release_mem_region(res->start, res->end - res->start + 1);
+       platform_set_drvdata(pdev, NULL);
+
+       if (wdev->armwdt_ck) {
+               clk_put(wdev->armwdt_ck);
+               wdev->armwdt_ck = NULL;
+       }
+
+       if (wdev->mpu_wdt_ick) {
+               clk_put(wdev->mpu_wdt_ick);
+               wdev->mpu_wdt_ick = NULL;
+       }
+
+       if (wdev->mpu_wdt_fck) {
+               clk_put(wdev->mpu_wdt_fck);
+               wdev->mpu_wdt_fck = NULL;
+       }
+       iounmap(wdev->base);
+
+       kfree(wdev);
+       omap_wdt_dev = NULL;
+
        return 0;
 }
 
@@ -344,17 +449,23 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       if (omap_wdt_users)
-               omap_wdt_disable();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users)
+               omap_wdt_disable(wdev);
+
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       if (omap_wdt_users) {
-               omap_wdt_enable();
-               omap_wdt_ping();
+       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+
+       if (wdev->omap_wdt_users) {
+               omap_wdt_enable(wdev);
+               omap_wdt_ping(wdev);
        }
+
        return 0;
 }
 
index 52a532a5114a94795e715d554e5aa57c584917ce..fc02ec6a03869a6a6bb0daa9889b1ebf10d558ec 100644 (file)
 #ifndef _OMAP_WATCHDOG_H
 #define _OMAP_WATCHDOG_H
 
-#define OMAP1610_WATCHDOG_BASE         0xfffeb000
-#define OMAP2420_WATCHDOG_BASE         0x48022000      /*WDT Timer 2 */
-
-#ifdef CONFIG_ARCH_OMAP24XX
-#define OMAP_WATCHDOG_BASE             OMAP2420_WATCHDOG_BASE
-#else
-#define OMAP_WATCHDOG_BASE             OMAP1610_WATCHDOG_BASE
-#define RM_RSTST_WKUP                  0
-#endif
-
-#define OMAP_WATCHDOG_REV              (OMAP_WATCHDOG_BASE + 0x00)
-#define OMAP_WATCHDOG_SYS_CONFIG       (OMAP_WATCHDOG_BASE + 0x10)
-#define OMAP_WATCHDOG_STATUS           (OMAP_WATCHDOG_BASE + 0x14)
-#define OMAP_WATCHDOG_CNTRL            (OMAP_WATCHDOG_BASE + 0x24)
-#define OMAP_WATCHDOG_CRR              (OMAP_WATCHDOG_BASE + 0x28)
-#define OMAP_WATCHDOG_LDR              (OMAP_WATCHDOG_BASE + 0x2c)
-#define OMAP_WATCHDOG_TGR              (OMAP_WATCHDOG_BASE + 0x30)
-#define OMAP_WATCHDOG_WPS              (OMAP_WATCHDOG_BASE + 0x34)
-#define OMAP_WATCHDOG_SPR              (OMAP_WATCHDOG_BASE + 0x48)
+#define OMAP_WATCHDOG_REV              (0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG       (0x10)
+#define OMAP_WATCHDOG_STATUS           (0x14)
+#define OMAP_WATCHDOG_CNTRL            (0x24)
+#define OMAP_WATCHDOG_CRR              (0x28)
+#define OMAP_WATCHDOG_LDR              (0x2c)
+#define OMAP_WATCHDOG_TGR              (0x30)
+#define OMAP_WATCHDOG_WPS              (0x34)
+#define OMAP_WATCHDOG_SPR              (0x48)
 
 /* Using the prescaler, the OMAP watchdog could go for many
  * months before firing.  These limits work without scaling,
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
new file mode 100644 (file)
index 0000000..14a339f
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * drivers/watchdog/orion5x_wdt.c
+ *
+ * Watchdog driver for Orion5x processors
+ *
+ * Author: Sylver Bruneau <sylver.bruneau@googlemail.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+/*
+ * Watchdog timer block registers.
+ */
+#define TIMER_CTRL             (TIMER_VIRT_BASE + 0x0000)
+#define  WDT_EN                        0x0010
+#define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
+
+#define WDT_MAX_DURATION       (0xffffffff / ORION5X_TCLK)
+#define WDT_IN_USE             0
+#define WDT_OK_TO_CLOSE                1
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat =  WDT_MAX_DURATION;      /* (seconds) */
+static unsigned long wdt_status;
+static spinlock_t wdt_lock;
+
+static void wdt_enable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Set watchdog duration */
+       writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+
+       /* Clear watchdog timer interrupt */
+       reg = readl(BRIDGE_CAUSE);
+       reg &= ~WDT_INT_REQ;
+       writel(reg, BRIDGE_CAUSE);
+
+       /* Enable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg |= WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       /* Enable reset on watchdog */
+       reg = readl(CPU_RESET_MASK);
+       reg |= WDT_RESET;
+       writel(reg, CPU_RESET_MASK);
+
+       spin_unlock(&wdt_lock);
+}
+
+static void wdt_disable(void)
+{
+       u32 reg;
+
+       spin_lock(&wdt_lock);
+
+       /* Disable reset on watchdog */
+       reg = readl(CPU_RESET_MASK);
+       reg &= ~WDT_RESET;
+       writel(reg, CPU_RESET_MASK);
+
+       /* Disable watchdog timer */
+       reg = readl(TIMER_CTRL);
+       reg &= ~WDT_EN;
+       writel(reg, TIMER_CTRL);
+
+       spin_unlock(&wdt_lock);
+}
+
+static int orion5x_wdt_get_timeleft(int *time_left)
+{
+       spin_lock(&wdt_lock);
+       *time_left = readl(WDT_VAL) / ORION5X_TCLK;
+       spin_unlock(&wdt_lock);
+       return 0;
+}
+
+static int orion5x_wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+               return -EBUSY;
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+       wdt_enable();
+       return nonseekable_open(inode, file);
+}
+
+static ssize_t orion5x_wdt_write(struct file *file, const char *data,
+                                       size_t len, loff_t *ppos)
+{
+       if (len) {
+               if (!nowayout) {
+                       size_t i;
+
+                       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       for (i = 0; i != len; i++) {
+                               char c;
+
+                               if (get_user(c, data + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+                       }
+               }
+               wdt_enable();
+       }
+       return len;
+}
+
+static struct watchdog_info ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING,
+       .identity       = "Orion5x Watchdog",
+};
+
+
+static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       int ret = -ENOTTY;
+       int time;
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               ret = copy_to_user((struct watchdog_info *)arg, &ident,
+                                  sizeof(ident)) ? -EFAULT : 0;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               ret = put_user(0, (int *)arg);
+               break;
+
+       case WDIOC_KEEPALIVE:
+               wdt_enable();
+               ret = 0;
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               ret = get_user(time, (int *)arg);
+               if (ret)
+                       break;
+
+               if (time <= 0 || time > WDT_MAX_DURATION) {
+                       ret = -EINVAL;
+                       break;
+               }
+               heartbeat = time;
+               wdt_enable();
+               /* Fall through */
+
+       case WDIOC_GETTIMEOUT:
+               ret = put_user(heartbeat, (int *)arg);
+               break;
+
+       case WDIOC_GETTIMELEFT:
+               if (orion5x_wdt_get_timeleft(&time)) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = put_user(time, (int *)arg);
+               break;
+       }
+       return ret;
+}
+
+static int orion5x_wdt_release(struct inode *inode, struct file *file)
+{
+       if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+               wdt_disable();
+       else
+               printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+                                       "timer will not stop\n");
+       clear_bit(WDT_IN_USE, &wdt_status);
+       clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+       return 0;
+}
+
+
+static const struct file_operations orion5x_wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = orion5x_wdt_write,
+       .unlocked_ioctl = orion5x_wdt_ioctl,
+       .open           = orion5x_wdt_open,
+       .release        = orion5x_wdt_release,
+};
+
+static struct miscdevice orion5x_wdt_miscdev = {
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &orion5x_wdt_fops,
+};
+
+static int __init orion5x_wdt_init(void)
+{
+       int ret;
+
+       spin_lock_init(&wdt_lock);
+
+       ret = misc_register(&orion5x_wdt_miscdev);
+       if (ret == 0)
+               printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
+                                                               heartbeat);
+
+       return ret;
+}
+
+static void __exit orion5x_wdt_exit(void)
+{
+       misc_deregister(&orion5x_wdt_miscdev);
+}
+
+module_init(orion5x_wdt_init);
+module_exit(orion5x_wdt_exit);
+
+MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
+MODULE_DESCRIPTION("Orion5x Processor Watchdog");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
+                                       __MODULE_STRING(WDT_MAX_DURATION) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
similarity index 51%
rename from drivers/sbus/char/riowatchdog.c
rename to drivers/watchdog/riowd.c
index 88c0fc6395e140acae5f610cd3126d6449af1572..09cb1833ea27a754be67934c98d12396f3f623a7 100644 (file)
@@ -1,7 +1,6 @@
-/* $Id: riowatchdog.c,v 1.3.2.2 2002/01/23 18:48:02 davem Exp $
- * riowatchdog.c - driver for hw watchdog inside Super I/O of RIO
+/* riowd.c - driver for hw watchdog inside Super I/O of RIO
  *
- * Copyright (C) 2001 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2001, 2008 David S. Miller (davem@davemloft.net)
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
+#include <linux/watchdog.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/io.h>
-#include <asm/ebus.h>
-#include <asm/bbc.h>
-#include <asm/oplib.h>
 #include <asm/uaccess.h>
 
-#include <asm/watchdog.h>
 
 /* RIO uses the NatSemi Super I/O power management logical device
  * as its' watchdog.
  * The watchdog device generates no interrupts.
  */
 
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
 MODULE_DESCRIPTION("Hardware watchdog driver for Sun RIO");
 MODULE_SUPPORTED_DEVICE("watchdog");
 MODULE_LICENSE("GPL");
 
-#define RIOWD_NAME     "pmc"
-#define RIOWD_MINOR    215
+#define DRIVER_NAME    "riowd"
+#define PFX            DRIVER_NAME ": "
 
-static DEFINE_SPINLOCK(riowd_lock);
+struct riowd {
+       void __iomem            *regs;
+       spinlock_t              lock;
+};
+
+static struct riowd *riowd_device;
 
-static void __iomem *bbc_regs;
-static void __iomem *riowd_regs;
 #define WDTO_INDEX     0x05
 
 static int riowd_timeout = 1;          /* in minutes */
 module_param(riowd_timeout, int, 0);
 MODULE_PARM_DESC(riowd_timeout, "Watchdog timeout in minutes");
 
-#if 0 /* Currently unused. */
-static u8 riowd_readreg(int index)
+static void riowd_writereg(struct riowd *p, u8 val, int index)
 {
        unsigned long flags;
-       u8 ret;
 
-       spin_lock_irqsave(&riowd_lock, flags);
-       writeb(index, riowd_regs + 0);
-       ret = readb(riowd_regs + 1);
-       spin_unlock_irqrestore(&riowd_lock, flags);
-
-       return ret;
-}
-#endif
-
-static void riowd_writereg(u8 val, int index)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&riowd_lock, flags);
-       writeb(index, riowd_regs + 0);
-       writeb(val, riowd_regs + 1);
-       spin_unlock_irqrestore(&riowd_lock, flags);
-}
-
-static void riowd_pingtimer(void)
-{
-       riowd_writereg(riowd_timeout, WDTO_INDEX);
-}
-
-static void riowd_stoptimer(void)
-{
-       u8 val;
-
-       riowd_writereg(0, WDTO_INDEX);
-
-       val = readb(bbc_regs + BBC_WDACTION);
-       val &= ~BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
-}
-
-static void riowd_starttimer(void)
-{
-       u8 val;
-
-       riowd_writereg(riowd_timeout, WDTO_INDEX);
-
-       val = readb(bbc_regs + BBC_WDACTION);
-       val |= BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
+       spin_lock_irqsave(&p->lock, flags);
+       writeb(index, p->regs + 0);
+       writeb(val, p->regs + 1);
+       spin_unlock_irqrestore(&p->lock, flags);
 }
 
 static int riowd_open(struct inode *inode, struct file *filp)
@@ -131,9 +90,12 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                       unsigned int cmd, unsigned long arg)
 {
        static struct watchdog_info info = {
-               WDIOF_SETTIMEOUT, 0, "Natl. Semiconductor PC97317"
+               .options                = WDIOF_SETTIMEOUT,
+               .firmware_version       = 1,
+               .identity               = DRIVER_NAME,
        };
        void __user *argp = (void __user *)arg;
+       struct riowd *p = riowd_device;
        unsigned int options;
        int new_margin;
 
@@ -150,7 +112,7 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                break;
 
        case WDIOC_KEEPALIVE:
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                break;
 
        case WDIOC_SETOPTIONS:
@@ -158,9 +120,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                        return -EFAULT;
 
                if (options & WDIOS_DISABLECARD)
-                       riowd_stoptimer();
+                       riowd_writereg(p, 0, WDTO_INDEX);
                else if (options & WDIOS_ENABLECARD)
-                       riowd_starttimer();
+                       riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                else
                        return -EINVAL;
 
@@ -170,9 +132,9 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
                if (get_user(new_margin, (int __user *)argp))
                        return -EFAULT;
                if ((new_margin < 60) || (new_margin > (255 * 60)))
-                   return -EINVAL;
+                       return -EINVAL;
                riowd_timeout = (new_margin + 59) / 60;
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                /* Fall */
 
        case WDIOC_GETTIMEOUT:
@@ -187,8 +149,10 @@ static int riowd_ioctl(struct inode *inode, struct file *filp,
 
 static ssize_t riowd_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
+       struct riowd *p = riowd_device;
+
        if (count) {
-               riowd_pingtimer();
+               riowd_writereg(p, riowd_timeout, WDTO_INDEX);
                return 1;
        }
 
@@ -197,99 +161,99 @@ static ssize_t riowd_write(struct file *file, const char __user *buf, size_t cou
 
 static const struct file_operations riowd_fops = {
        .owner =        THIS_MODULE,
+       .llseek =       no_llseek,
        .ioctl =        riowd_ioctl,
        .open =         riowd_open,
        .write =        riowd_write,
        .release =      riowd_release,
 };
 
-static struct miscdevice riowd_miscdev = { RIOWD_MINOR, RIOWD_NAME, &riowd_fops };
+static struct miscdevice riowd_miscdev = {
+       .minor  = WATCHDOG_MINOR,
+       .name   = "watchdog",
+       .fops   = &riowd_fops
+};
 
-static int __init riowd_bbc_init(void)
+static int __devinit riowd_probe(struct of_device *op,
+                                const struct of_device_id *match)
 {
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-       u8 val;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, "bbc"))
-                               goto found_bbc;
-               }
-       }
+       struct riowd *p;
+       int err = -EINVAL;
 
-found_bbc:
-       if (!edev)
-               return -ENODEV;
-       bbc_regs = ioremap(edev->resource[0].start, BBC_REGS_SIZE);
-       if (!bbc_regs)
-               return -ENODEV;
+       if (riowd_device)
+               goto out;
 
-       /* Turn it off. */
-       val = readb(bbc_regs + BBC_WDACTION);
-       val &= ~BBC_WDACTION_RST;
-       writeb(val, bbc_regs + BBC_WDACTION);
+       err = -ENOMEM;
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p)
+               goto out;
 
-       return 0;
-}
+       spin_lock_init(&p->lock);
 
-static int __init riowd_init(void)
-{
-       struct  linux_ebus *ebus = NULL;
-       struct  linux_ebus_device *edev = NULL;
-
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
-                               goto ebus_done;
-               }
+       p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME);
+       if (!p->regs) {
+               printk(KERN_ERR PFX "Cannot map registers.\n");
+               goto out_free;
        }
 
-ebus_done:
-       if (!edev)
-               goto fail;
-
-       riowd_regs = ioremap(edev->resource[0].start, 2);
-       if (riowd_regs == NULL) {
-               printk(KERN_ERR "pmc: Cannot map registers.\n");
-               return -ENODEV;
+       err = misc_register(&riowd_miscdev);
+       if (err) {
+               printk(KERN_ERR PFX "Cannot register watchdog misc device.\n");
+               goto out_iounmap;
        }
 
-       if (riowd_bbc_init()) {
-               printk(KERN_ERR "pmc: Failure initializing BBC config.\n");
-               goto fail;
-       }
+       printk(KERN_INFO PFX "Hardware watchdog [%i minutes], "
+              "regs at %p\n", riowd_timeout, p->regs);
 
-       if (misc_register(&riowd_miscdev)) {
-               printk(KERN_ERR "pmc: Cannot register watchdog misc device.\n");
-               goto fail;
-       }
+       dev_set_drvdata(&op->dev, p);
+       riowd_device = p;
+       err = 0;
 
-       printk(KERN_INFO "pmc: Hardware watchdog [%i minutes], "
-              "regs at %p\n", riowd_timeout, riowd_regs);
+out_iounmap:
+       of_iounmap(&op->resource[0], p->regs, 2);
 
-       return 0;
+out_free:
+       kfree(p);
 
-fail:
-       if (riowd_regs) {
-               iounmap(riowd_regs);
-               riowd_regs = NULL;
-       }
-       if (bbc_regs) {
-               iounmap(bbc_regs);
-               bbc_regs = NULL;
-       }
-       return -ENODEV;
+out:
+       return err;
 }
 
-static void __exit riowd_cleanup(void)
+static int __devexit riowd_remove(struct of_device *op)
 {
+       struct riowd *p = dev_get_drvdata(&op->dev);
+
        misc_deregister(&riowd_miscdev);
-       iounmap(riowd_regs);
-       riowd_regs = NULL;
-       iounmap(bbc_regs);
-       bbc_regs = NULL;
+       of_iounmap(&op->resource[0], p->regs, 2);
+       kfree(p);
+
+       return 0;
+}
+
+static const struct of_device_id riowd_match[] = {
+       {
+               .name = "pmc",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, riowd_match);
+
+static struct of_platform_driver riowd_driver = {
+       .name           = DRIVER_NAME,
+       .match_table    = riowd_match,
+       .probe          = riowd_probe,
+       .remove         = __devexit_p(riowd_remove),
+};
+
+static int __init riowd_init(void)
+{
+       return of_register_driver(&riowd_driver, &of_bus_type);
+}
+
+static void __exit riowd_exit(void)
+{
+       of_unregister_driver(&riowd_driver);
 }
 
 module_init(riowd_init);
-module_exit(riowd_cleanup);
+module_exit(riowd_exit);
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
new file mode 100644 (file)
index 0000000..c73b5e2
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ *     w83697ug/uf WDT driver
+ *
+ *     (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
+ *              reused original code to supoprt w83697ug/uf.
+ *
+ *     Based on w83627hf_wdt.c which is based on advantechwdt.c
+ *     which is based on wdt.c.
+ *     Original copyright messages:
+ *
+ *     (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ *             added support for W83627THF.
+ *
+ *     (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *
+ *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *                             http://www.redhat.com
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License
+ *     as published by the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ *     warranty for any of this software. This material is provided
+ *     "AS-IS" and at no charge.
+ *
+ *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+
+#define WATCHDOG_NAME "w83697ug/uf WDT"
+#define PFX WATCHDOG_NAME ": "
+#define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
+
+static unsigned long wdt_is_open;
+static char expect_close;
+static DEFINE_SPINLOCK(io_lock);
+
+static int wdt_io = 0x2e;
+module_param(wdt_io, int, 0);
+MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
+
+static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. 1<= timeout <=255 (default="
+                               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ *     Kernel methods.
+ */
+
+#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
+#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
+                                                       (same as EFER) */
+#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
+
+static void w83697ug_select_wd_register(void)
+{
+       unsigned char c;
+       unsigned char version;
+
+       outb_p(0x87, WDT_EFER); /* Enter extended function mode */
+       outb_p(0x87, WDT_EFER); /* Again according to manual */
+
+       outb(0x20, WDT_EFER);   /* check chip version   */
+       version = inb(WDT_EFDR);
+
+       if (version == 0x68) {  /* W83697UG             */
+               printk(KERN_INFO PFX "Watchdog chip version 0x%02x = "
+                       "W83697UG/UF found at 0x%04x\n", version, wdt_io);
+
+               outb_p(0x2b, WDT_EFER);
+               c = inb_p(WDT_EFDR);    /* select WDT0 */
+               c &= ~0x04;
+               outb_p(0x2b, WDT_EFER);
+               outb_p(c, WDT_EFDR);    /* set pin118 to WDT0 */
+
+       } else {
+               printk(KERN_ERR PFX "No W83697UG/UF could be found\n");
+               return -EIO;
+       }
+
+       outb_p(0x07, WDT_EFER); /* point to logical device number reg */
+       outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
+       outb_p(0x30, WDT_EFER); /* select CR30 */
+       c = inb_p(WDT_EFDR);
+       outb_p(c || 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
+}
+
+static void w83697ug_unselect_wd_register(void)
+{
+       outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
+}
+
+static void w83697ug_init(void)
+{
+       unsigned char t;
+
+       w83697ug_select_wd_register();
+
+       outb_p(0xF6, WDT_EFER); /* Select CRF6 */
+       t = inb_p(WDT_EFDR);    /* read CRF6 */
+       if (t != 0) {
+               printk(KERN_INFO PFX "Watchdog already running."
+                       " Resetting timeout to %d sec\n", timeout);
+               outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
+       }
+       outb_p(0xF5, WDT_EFER); /* Select CRF5 */
+       t = inb_p(WDT_EFDR);    /* read CRF5 */
+       t &= ~0x0C;             /* set second mode &
+                                       disable keyboard turning off watchdog */
+       outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
+
+       w83697ug_unselect_wd_register();
+}
+
+static void wdt_ctrl(int timeout)
+{
+       spin_lock(&io_lock);
+
+       w83697ug_select_wd_register();
+
+       outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
+       outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
+
+       w83697ug_unselect_wd_register();
+
+       spin_unlock(&io_lock);
+}
+
+static int wdt_ping(void)
+{
+       wdt_ctrl(timeout);
+       return 0;
+}
+
+static int wdt_disable(void)
+{
+       wdt_ctrl(0);
+       return 0;
+}
+
+static int wdt_set_heartbeat(int t)
+{
+       if (t < 1 || t > 255)
+               return -EINVAL;
+
+       timeout = t;
+       return 0;
+}
+
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+                                               size_t count, loff_t *ppos)
+{
+       if (count) {
+               if (!nowayout) {
+                       size_t i;
+
+                       expect_close = 0;
+
+                       for (i = 0; i != count; i++) {
+                               char c;
+                               if (get_user(c, buf + i))
+                                       return -EFAULT;
+                               if (c == 'V')
+                                       expect_close = 42;
+                       }
+               }
+               wdt_ping();
+       }
+       return count;
+}
+
+static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
+       int new_timeout;
+       static const struct watchdog_info ident = {
+               .options =              WDIOF_KEEPALIVEPING |
+                                       WDIOF_SETTIMEOUT |
+                                       WDIOF_MAGICCLOSE,
+               .firmware_version =     1,
+               .identity =             "W83697UG WDT",
+       };
+
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &ident, sizeof(ident)))
+                       return -EFAULT;
+               break;
+
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(0, p);
+
+       case WDIOC_SETOPTIONS:
+       {
+               int options, retval = -EINVAL;
+
+               if (get_user(options, p))
+                       return -EFAULT;
+
+               if (options & WDIOS_DISABLECARD) {
+                       wdt_disable();
+                       retval = 0;
+               }
+
+               if (options & WDIOS_ENABLECARD) {
+                       wdt_ping();
+                       retval = 0;
+               }
+
+               return retval;
+       }
+
+       case WDIOC_KEEPALIVE:
+               wdt_ping();
+               break;
+
+       case WDIOC_SETTIMEOUT:
+               if (get_user(new_timeout, p))
+                       return -EFAULT;
+               if (wdt_set_heartbeat(new_timeout))
+                       return -EINVAL;
+               wdt_ping();
+               /* Fall */
+
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, p);
+
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static int wdt_open(struct inode *inode, struct file *file)
+{
+       if (test_and_set_bit(0, &wdt_is_open))
+               return -EBUSY;
+       /*
+        *      Activate
+        */
+
+       wdt_ping();
+       return nonseekable_open(inode, file);
+}
+
+static int wdt_close(struct inode *inode, struct file *file)
+{
+       if (expect_close == 42)
+               wdt_disable();
+       else {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
+               wdt_ping();
+       }
+       expect_close = 0;
+       clear_bit(0, &wdt_is_open);
+       return 0;
+}
+
+/*
+ *     Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+       void *unused)
+{
+       if (code == SYS_DOWN || code == SYS_HALT)
+               wdt_disable();  /* Turn the WDT off */
+
+       return NOTIFY_DONE;
+}
+
+/*
+ *     Kernel Interfaces
+ */
+
+static const struct file_operations wdt_fops = {
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = wdt_write,
+       .unlocked_ioctl = wdt_ioctl,
+       .open           = wdt_open,
+       .release        = wdt_close,
+};
+
+static struct miscdevice wdt_miscdev = {
+       .minor = WATCHDOG_MINOR,
+       .name = "watchdog",
+       .fops = &wdt_fops,
+};
+
+/*
+ *     The WDT needs to learn about soft shutdowns in order to
+ *     turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier = {
+       .notifier_call = wdt_notify_sys,
+};
+
+static int __init wdt_init(void)
+{
+       int ret;
+
+       printk(KERN_INFO "WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising.\n");
+
+       if (wdt_set_heartbeat(timeout)) {
+               wdt_set_heartbeat(WATCHDOG_TIMEOUT);
+               printk(KERN_INFO PFX
+                       "timeout value must be 1<=timeout<=255, using %d\n",
+                       WATCHDOG_TIMEOUT);
+       }
+
+       if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
+               printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+                       wdt_io);
+               ret = -EIO;
+               goto out;
+       }
+
+       w83697ug_init();
+
+       ret = register_reboot_notifier(&wdt_notifier);
+       if (ret != 0) {
+               printk(KERN_ERR PFX
+                       "cannot register reboot notifier (err=%d)\n", ret);
+               goto unreg_regions;
+       }
+
+       ret = misc_register(&wdt_miscdev);
+       if (ret != 0) {
+               printk(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                       WATCHDOG_MINOR, ret);
+               goto unreg_reboot;
+       }
+
+       printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
+               timeout, nowayout);
+
+out:
+       return ret;
+unreg_reboot:
+       unregister_reboot_notifier(&wdt_notifier);
+unreg_regions:
+       release_region(wdt_io, 1);
+       goto out;
+}
+
+static void __exit wdt_exit(void)
+{
+       misc_deregister(&wdt_miscdev);
+       unregister_reboot_notifier(&wdt_notifier);
+       release_region(wdt_io, 1);
+}
+
+module_init(wdt_init);
+module_exit(wdt_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
+MODULE_DESCRIPTION("w83697ug/uf WDT driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 363286c542906e8fde4e5fb6f87ac718938cf55e..d2a8fdf0e1918c7ada49c7a1c5c369647ddbeafd 100644 (file)
@@ -1,4 +1,5 @@
 obj-y  += grant-table.o features.o events.o manage.o
 obj-y  += xenbus/
+obj-$(CONFIG_HOTPLUG_CPU)      += cpu_hotplug.o
 obj-$(CONFIG_XEN_XENCOMM)      += xencomm.o
 obj-$(CONFIG_XEN_BALLOON)      += balloon.o
index 2e15da5459cf6bd5b0e144a0fef70cccfa6549c3..8c83abc73400c48ee6a21013af1548de8f275f57 100644 (file)
@@ -53,7 +53,6 @@
 #include <asm/tlb.h>
 
 #include <xen/interface/memory.h>
-#include <xen/balloon.h>
 #include <xen/xenbus.h>
 #include <xen/features.h>
 #include <xen/page.h>
@@ -226,9 +225,8 @@ static int increase_reservation(unsigned long nr_pages)
        }
 
        set_xen_guest_handle(reservation.extent_start, frame_list);
-       reservation.nr_extents   = nr_pages;
-       rc = HYPERVISOR_memory_op(
-               XENMEM_populate_physmap, &reservation);
+       reservation.nr_extents = nr_pages;
+       rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
        if (rc < nr_pages) {
                if (rc > 0) {
                        int ret;
@@ -236,7 +234,7 @@ static int increase_reservation(unsigned long nr_pages)
                        /* We hit the Xen hard limit: reprobe. */
                        reservation.nr_extents = rc;
                        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-                                       &reservation);
+                                                  &reservation);
                        BUG_ON(ret != rc);
                }
                if (rc >= 0)
@@ -420,7 +418,7 @@ static int __init balloon_init(void)
        unsigned long pfn;
        struct page *page;
 
-       if (!is_running_on_xen())
+       if (!xen_pv_domain())
                return -ENODEV;
 
        pr_info("xen_balloon: Initialising balloon driver.\n");
@@ -464,136 +462,13 @@ static void balloon_exit(void)
 
 module_exit(balloon_exit);
 
-static void balloon_update_driver_allowance(long delta)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       balloon_stats.driver_pages += delta;
-       spin_unlock_irqrestore(&balloon_lock, flags);
-}
-
-static int dealloc_pte_fn(
-       pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
-{
-       unsigned long mfn = pte_mfn(*pte);
-       int ret;
-       struct xen_memory_reservation reservation = {
-               .nr_extents   = 1,
-               .extent_order = 0,
-               .domid        = DOMID_SELF
-       };
-       set_xen_guest_handle(reservation.extent_start, &mfn);
-       set_pte_at(&init_mm, addr, pte, __pte_ma(0ull));
-       set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
-       ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
-       BUG_ON(ret != 1);
-       return 0;
-}
-
-static struct page **alloc_empty_pages_and_pagevec(int nr_pages)
-{
-       unsigned long vaddr, flags;
-       struct page *page, **pagevec;
-       int i, ret;
-
-       pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
-       if (pagevec == NULL)
-               return NULL;
-
-       for (i = 0; i < nr_pages; i++) {
-               page = pagevec[i] = alloc_page(GFP_KERNEL);
-               if (page == NULL)
-                       goto err;
-
-               vaddr = (unsigned long)page_address(page);
-
-               scrub_page(page);
-
-               spin_lock_irqsave(&balloon_lock, flags);
-
-               if (xen_feature(XENFEAT_auto_translated_physmap)) {
-                       unsigned long gmfn = page_to_pfn(page);
-                       struct xen_memory_reservation reservation = {
-                               .nr_extents   = 1,
-                               .extent_order = 0,
-                               .domid        = DOMID_SELF
-                       };
-                       set_xen_guest_handle(reservation.extent_start, &gmfn);
-                       ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-                                                  &reservation);
-                       if (ret == 1)
-                               ret = 0; /* success */
-               } else {
-                       ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
-                                                 dealloc_pte_fn, NULL);
-               }
-
-               if (ret != 0) {
-                       spin_unlock_irqrestore(&balloon_lock, flags);
-                       __free_page(page);
-                       goto err;
-               }
-
-               totalram_pages = --balloon_stats.current_pages;
-
-               spin_unlock_irqrestore(&balloon_lock, flags);
-       }
-
- out:
-       schedule_work(&balloon_worker);
-       flush_tlb_all();
-       return pagevec;
-
- err:
-       spin_lock_irqsave(&balloon_lock, flags);
-       while (--i >= 0)
-               balloon_append(pagevec[i]);
-       spin_unlock_irqrestore(&balloon_lock, flags);
-       kfree(pagevec);
-       pagevec = NULL;
-       goto out;
-}
-
-static void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
-{
-       unsigned long flags;
-       int i;
-
-       if (pagevec == NULL)
-               return;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       for (i = 0; i < nr_pages; i++) {
-               BUG_ON(page_count(pagevec[i]) != 1);
-               balloon_append(pagevec[i]);
-       }
-       spin_unlock_irqrestore(&balloon_lock, flags);
-
-       kfree(pagevec);
-
-       schedule_work(&balloon_worker);
-}
-
-static void balloon_release_driver_page(struct page *page)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&balloon_lock, flags);
-       balloon_append(page);
-       balloon_stats.driver_pages--;
-       spin_unlock_irqrestore(&balloon_lock, flags);
-
-       schedule_work(&balloon_worker);
-}
-
-
-#define BALLOON_SHOW(name, format, args...)                    \
-       static ssize_t show_##name(struct sys_device *dev,      \
-                                  char *buf)                   \
-       {                                                       \
-               return sprintf(buf, format, ##args);            \
-       }                                                       \
+#define BALLOON_SHOW(name, format, args...)                            \
+       static ssize_t show_##name(struct sys_device *dev,              \
+                                  struct sysdev_attribute *attr,       \
+                                  char *buf)                           \
+       {                                                               \
+               return sprintf(buf, format, ##args);                    \
+       }                                                               \
        static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
 
 BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
@@ -604,7 +479,8 @@ BALLOON_SHOW(hard_limit_kb,
             (balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
 BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));
 
-static ssize_t show_target_kb(struct sys_device *dev, char *buf)
+static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
+                             char *buf)
 {
        return sprintf(buf, "%lu\n", PAGES2KB(balloon_stats.target_pages));
 }
@@ -614,19 +490,14 @@ static ssize_t store_target_kb(struct sys_device *dev,
                               const char *buf,
                               size_t count)
 {
-       char memstring[64], *endchar;
+       char *endchar;
        unsigned long long target_bytes;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (count <= 1)
-               return -EBADMSG; /* runt */
-       if (count > sizeof(memstring))
-               return -EFBIG;   /* too long */
-       strcpy(memstring, buf);
+       target_bytes = memparse(buf, &endchar);
 
-       target_bytes = memparse(memstring, &endchar);
        balloon_set_new_target(target_bytes >> PAGE_SHIFT);
 
        return count;
@@ -694,20 +565,4 @@ static int register_balloon(struct sys_device *sysdev)
        return error;
 }
 
-static void unregister_balloon(struct sys_device *sysdev)
-{
-       int i;
-
-       sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
-       for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
-               sysdev_remove_file(sysdev, balloon_attrs[i]);
-       sysdev_unregister(sysdev);
-       sysdev_class_unregister(&balloon_sysdev_class);
-}
-
-static void balloon_sysfs_exit(void)
-{
-       unregister_balloon(&balloon_sysdev);
-}
-
 MODULE_LICENSE("GPL");
diff --git a/drivers/xen/cpu_hotplug.c b/drivers/xen/cpu_hotplug.c
new file mode 100644 (file)
index 0000000..565280e
--- /dev/null
@@ -0,0 +1,90 @@
+#include <linux/notifier.h>
+
+#include <xen/xenbus.h>
+
+#include <asm-x86/xen/hypervisor.h>
+#include <asm/cpu.h>
+
+static void enable_hotplug_cpu(int cpu)
+{
+       if (!cpu_present(cpu))
+               arch_register_cpu(cpu);
+
+       cpu_set(cpu, cpu_present_map);
+}
+
+static void disable_hotplug_cpu(int cpu)
+{
+       if (cpu_present(cpu))
+               arch_unregister_cpu(cpu);
+
+       cpu_clear(cpu, cpu_present_map);
+}
+
+static void vcpu_hotplug(unsigned int cpu)
+{
+       int err;
+       char dir[32], state[32];
+
+       if (!cpu_possible(cpu))
+               return;
+
+       sprintf(dir, "cpu/%u", cpu);
+       err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
+       if (err != 1) {
+               printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
+               return;
+       }
+
+       if (strcmp(state, "online") == 0) {
+               enable_hotplug_cpu(cpu);
+       } else if (strcmp(state, "offline") == 0) {
+               (void)cpu_down(cpu);
+               disable_hotplug_cpu(cpu);
+       } else {
+               printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
+                      state, cpu);
+       }
+}
+
+static void handle_vcpu_hotplug_event(struct xenbus_watch *watch,
+                                       const char **vec, unsigned int len)
+{
+       unsigned int cpu;
+       char *cpustr;
+       const char *node = vec[XS_WATCH_PATH];
+
+       cpustr = strstr(node, "cpu/");
+       if (cpustr != NULL) {
+               sscanf(cpustr, "cpu/%u", &cpu);
+               vcpu_hotplug(cpu);
+       }
+}
+
+static int setup_cpu_watcher(struct notifier_block *notifier,
+                             unsigned long event, void *data)
+{
+       static struct xenbus_watch cpu_watch = {
+               .node = "cpu",
+               .callback = handle_vcpu_hotplug_event};
+
+       (void)register_xenbus_watch(&cpu_watch);
+
+       return NOTIFY_DONE;
+}
+
+static int __init setup_vcpu_hotplug_event(void)
+{
+       static struct notifier_block xsn_cpu = {
+               .notifier_call = setup_cpu_watcher };
+
+       if (!xen_pv_domain())
+               return -ENODEV;
+
+       register_xenstore_notifier(&xsn_cpu);
+
+       return 0;
+}
+
+arch_initcall(setup_vcpu_hotplug_event);
+
index 0e0c28574af8701213d35dac28ca8308d03e1029..c3290bc186a0e62c36db12cd8ef44c58f0a4f4b0 100644 (file)
@@ -84,17 +84,6 @@ static int irq_bindcount[NR_IRQS];
 /* Xen will never allocate port zero for any purpose. */
 #define VALID_EVTCHN(chn)      ((chn) != 0)
 
-/*
- * Force a proper event-channel callback from Xen after clearing the
- * callback mask. We do this in a very simple manner, by making a call
- * down into Xen. The pending flag will be checked by Xen on return.
- */
-void force_evtchn_callback(void)
-{
-       (void)HYPERVISOR_xen_version(0, NULL);
-}
-EXPORT_SYMBOL_GPL(force_evtchn_callback);
-
 static struct irq_chip xen_dynamic_chip;
 
 /* Constructor for packed IRQ information. */
@@ -175,6 +164,12 @@ static inline void set_evtchn(int port)
        sync_set_bit(port, &s->evtchn_pending[0]);
 }
 
+static inline int test_evtchn(int port)
+{
+       struct shared_info *s = HYPERVISOR_shared_info;
+       return sync_test_bit(port, &s->evtchn_pending[0]);
+}
+
 
 /**
  * notify_remote_via_irq - send event to remote end of event channel via irq
@@ -365,6 +360,10 @@ static void unbind_from_irq(unsigned int irq)
                        per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
                                [index_from_irq(irq)] = -1;
                        break;
+               case IRQT_IPI:
+                       per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
+                               [index_from_irq(irq)] = -1;
+                       break;
                default:
                        break;
                }
@@ -743,6 +742,25 @@ void xen_clear_irq_pending(int irq)
                clear_evtchn(evtchn);
 }
 
+void xen_set_irq_pending(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+
+       if (VALID_EVTCHN(evtchn))
+               set_evtchn(evtchn);
+}
+
+bool xen_test_irq_pending(int irq)
+{
+       int evtchn = evtchn_from_irq(irq);
+       bool ret = false;
+
+       if (VALID_EVTCHN(evtchn))
+               ret = test_evtchn(evtchn);
+
+       return ret;
+}
+
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
 void xen_poll_irq(int irq)
index e9e11168616af7a014b3d51db4a9ccc35208bbf5..06592b9da83c454a0117d8d9bf6c86633787e3d7 100644 (file)
@@ -508,7 +508,7 @@ static int __devinit gnttab_init(void)
        unsigned int max_nr_glist_frames, nr_glist_frames;
        unsigned int nr_init_grefs;
 
-       if (!is_running_on_xen())
+       if (!xen_domain())
                return -ENODEV;
 
        nr_grant_frames = 1;
index 57ceb5346b749338e153ccdbeaf4bf5ceb09c19f..7f24a98a446f53e0a7fd2bd0ec518494ca7e72cd 100644 (file)
@@ -814,7 +814,7 @@ static int __init xenbus_probe_init(void)
        DPRINTK("");
 
        err = -ENODEV;
-       if (!is_running_on_xen())
+       if (!xen_domain())
                goto out_error;
 
        /* Register ourselves with the kernel bus subsystem */
@@ -829,7 +829,7 @@ static int __init xenbus_probe_init(void)
        /*
         * Domain0 doesn't have a store_evtchn or store_mfn yet.
         */
-       if (is_initial_xendomain()) {
+       if (xen_initial_domain()) {
                /* dom0 not yet supported */
        } else {
                xenstored_ready = 1;
@@ -846,7 +846,7 @@ static int __init xenbus_probe_init(void)
                goto out_unreg_back;
        }
 
-       if (!is_initial_xendomain())
+       if (!xen_initial_domain())
                xenbus_probe(NULL);
 
        return 0;
@@ -937,7 +937,7 @@ static void wait_for_devices(struct xenbus_driver *xendrv)
        unsigned long timeout = jiffies + 10*HZ;
        struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
 
-       if (!ready_to_wait_for_devices || !is_running_on_xen())
+       if (!ready_to_wait_for_devices || !xen_domain())
                return;
 
        while (exists_disconnected_device(drv)) {
index 654d972a88f4022f9ec7d60a7277e21201b5bfb0..88786ba02d277fac25923893c29bb96206e42827 100644 (file)
@@ -311,8 +311,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
        buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;
        buffer->Pid = cpu_to_le16((__u16)current->tgid);
        buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));
-       spin_lock(&GlobalMid_Lock);
-       spin_unlock(&GlobalMid_Lock);
        if (treeCon) {
                buffer->Tid = treeCon->tid;
                if (treeCon->ses) {
index 33a6b7ecb8b8686449fb42b1ab5f8ef6ce64709f..d152856c371be4906b7effec1f3c42842a4cee2d 100644 (file)
@@ -226,6 +226,8 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
        return error;
 }
 
+#ifdef CONFIG_BLOCK
+
 #define blk_to_logical(inode, blk) (blk << (inode)->i_blkbits)
 #define logical_to_blk(inode, offset) (offset >> (inode)->i_blkbits);
 
@@ -342,6 +344,8 @@ int generic_block_fiemap(struct inode *inode,
 }
 EXPORT_SYMBOL(generic_block_fiemap);
 
+#endif  /*  CONFIG_BLOCK  */
+
 static int file_ioctl(struct file *filp, unsigned int cmd,
                unsigned long arg)
 {
index 8786e01e0db8060582590e8a4451f7387afdfd8b..969570167e9ef84e528d373ca88746c87acedfb9 100644 (file)
@@ -199,6 +199,8 @@ typedef struct siginfo {
  */
 #define TRAP_BRKPT     (__SI_FAULT|1)  /* process breakpoint */
 #define TRAP_TRACE     (__SI_FAULT|2)  /* process trace trap */
+#define TRAP_BRANCH     (__SI_FAULT|3)  /* process taken branch trap */
+#define TRAP_HWBKPT     (__SI_FAULT|4)  /* hardware breakpoint/watchpoint */
 #define NSIGTRAP       2
 
 /*
index d4909f55fe35d041a64736ee7b42da548cac56af..d7034728f3778cdfef8e3b6eedcd049005d40c17 100644 (file)
@@ -3,11 +3,6 @@
 
 #include <asm-generic/siginfo.h>
 
-/*
- * SIGTRAP si_codes
- */
-#define TRAP_BRANCH    (__SI_FAULT|3)  /* process taken branch trap */
-#define TRAP_HWBKPT    (__SI_FAULT|4)  /* hardware breakpoint or watchpoint */
 #undef NSIGTRAP
 #define NSIGTRAP       4
 
index ec42ed8745913383cbb81be7c28556c4ddbacdd0..79b4b88505d743eed1e0e5ad7c6e55df8dc63c3f 100644 (file)
@@ -16,4 +16,21 @@ static inline unsigned int get_bios_ebda(void)
 
 void reserve_ebda_region(void);
 
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+/*
+ * This is obviously not a great place for this, but we want to be
+ * able to scatter it around anywhere in the kernel.
+ */
+void check_for_bios_corruption(void);
+void start_periodic_check_for_corruption(void);
+#else
+static inline void check_for_bios_corruption(void)
+{
+}
+
+static inline void start_periodic_check_for_corruption(void)
+{
+}
+#endif
+
 #endif /* ASM_X86__BIOS_EBDA_H */
index 825de5dc867cb97240a90ba3abc1c2933f3fee07..1d63bd5d59462833cd5a458956c20a2d05618d9e 100644 (file)
@@ -2,9 +2,7 @@
 #define ASM_X86__BOOT_H
 
 /* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG    0x9000
 #define DEF_SYSSEG     0x1000
-#define DEF_SETUPSEG   0x9020
 #define DEF_SYSSIZE    0x7F00
 
 /* Internal svga startup constants */
index b73fea54def29e1dfd0d2e95ec65f08c64b5cb49..ebc307817e98cc2c7999c883066d6b06134f6a16 100644 (file)
@@ -24,6 +24,11 @@ static inline void fill_ldt(struct desc_struct *desc,
        desc->d = info->seg_32bit;
        desc->g = info->limit_in_pages;
        desc->base2 = (info->base_addr & 0xff000000) >> 24;
+       /*
+        * Don't allow setting of the lm bit. It is useless anyway
+        * because 64bit system calls require __USER_CS:
+        */
+       desc->l = 0;
 }
 
 extern struct desc_ptr idt_descr;
@@ -97,7 +102,15 @@ static inline int desc_empty(const void *ptr)
        native_write_gdt_entry(dt, entry, desc, type)
 #define write_idt_entry(dt, entry, g)          \
        native_write_idt_entry(dt, entry, g)
-#endif
+
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+}
+#endif /* CONFIG_PARAVIRT */
 
 static inline void native_write_idt_entry(gate_desc *idt, int entry,
                                          const gate_desc *gate)
diff --git a/include/asm-x86/microcode.h b/include/asm-x86/microcode.h
new file mode 100644 (file)
index 0000000..62c793b
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef ASM_X86__MICROCODE_H
+#define ASM_X86__MICROCODE_H
+
+struct cpu_signature {
+       unsigned int sig;
+       unsigned int pf;
+       unsigned int rev;
+};
+
+struct device;
+
+struct microcode_ops {
+       int  (*request_microcode_user) (int cpu, const void __user *buf, size_t size);
+       int  (*request_microcode_fw) (int cpu, struct device *device);
+
+       void (*apply_microcode) (int cpu);
+
+       int  (*collect_cpu_info) (int cpu, struct cpu_signature *csig);
+       void (*microcode_fini_cpu) (int cpu);
+};
+
+struct ucode_cpu_info {
+       struct cpu_signature cpu_sig;
+       int valid;
+       void *mc;
+};
+extern struct ucode_cpu_info ucode_cpu_info[];
+
+#ifdef CONFIG_MICROCODE_INTEL
+extern struct microcode_ops * __init init_intel_microcode(void);
+#else
+static inline struct microcode_ops * __init init_intel_microcode(void)
+{
+       return NULL;
+}
+#endif /* CONFIG_MICROCODE_INTEL */
+
+#ifdef CONFIG_MICROCODE_AMD
+extern struct microcode_ops * __init init_amd_microcode(void);
+#else
+static inline struct microcode_ops * __init init_amd_microcode(void)
+{
+       return NULL;
+}
+#endif
+
+#endif /* ASM_X86__MICROCODE_H */
index 626b03a14875b20d54e2885fae78a602507f8577..6480f3333b2a4edebecd7d76507dbd819c3da596 100644 (file)
@@ -7,7 +7,7 @@
 
 #ifdef CONFIG_NUMA
 
-#define VIRTUAL_BUG_ON(x)
+#include <linux/mmdebug.h>
 
 #include <asm/smp.h>
 
@@ -29,7 +29,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
 {
        unsigned nid;
        VIRTUAL_BUG_ON(!memnodemap);
-       VIRTUAL_BUG_ON((addr >> memnode_shift) >= memnodemapsize);
        nid = memnodemap[addr >> memnode_shift];
        VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
        return nid;
index 72f7305682c652d7ef2198b35e732d58544e808b..9c5a737a9af9878ee128d15a90505afd6f733737 100644 (file)
@@ -73,7 +73,12 @@ typedef struct page *pgtable_t;
 #endif
 
 #ifndef __ASSEMBLY__
+#define __phys_addr_const(x)   ((x) - PAGE_OFFSET)
+#ifdef CONFIG_DEBUG_VIRTUAL
+extern unsigned long __phys_addr(unsigned long);
+#else
 #define __phys_addr(x)         ((x) - PAGE_OFFSET)
+#endif
 #define __phys_reloc_hide(x)   RELOC_HIDE((x), 0)
 
 #ifdef CONFIG_FLATMEM
index d7d358a439960d43d782e4bbc5862b50d811c60b..8d6ae2f760d0000553d50ad9884722df23973406 100644 (file)
@@ -124,6 +124,9 @@ struct pv_cpu_ops {
                                int entrynum, const void *desc, int size);
        void (*write_idt_entry)(gate_desc *,
                                int entrynum, const gate_desc *gate);
+       void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries);
+       void (*free_ldt)(struct desc_struct *ldt, unsigned entries);
+
        void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t);
 
        void (*set_iopl_mask)(unsigned mask);
@@ -325,6 +328,7 @@ struct pv_lock_ops {
        int (*spin_is_locked)(struct raw_spinlock *lock);
        int (*spin_is_contended)(struct raw_spinlock *lock);
        void (*spin_lock)(struct raw_spinlock *lock);
+       void (*spin_lock_flags)(struct raw_spinlock *lock, unsigned long flags);
        int (*spin_trylock)(struct raw_spinlock *lock);
        void (*spin_unlock)(struct raw_spinlock *lock);
 };
@@ -830,6 +834,16 @@ do {                                                       \
        (aux) = __aux;                                  \
 } while (0)
 
+static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
+{
+       PVOP_VCALL2(pv_cpu_ops.alloc_ldt, ldt, entries);
+}
+
+static inline void paravirt_free_ldt(struct desc_struct *ldt, unsigned entries)
+{
+       PVOP_VCALL2(pv_cpu_ops.free_ldt, ldt, entries);
+}
+
 static inline void load_TR_desc(void)
 {
        PVOP_VCALL0(pv_cpu_ops.load_tr_desc);
@@ -1394,6 +1408,12 @@ static __always_inline void __raw_spin_lock(struct raw_spinlock *lock)
        PVOP_VCALL1(pv_lock_ops.spin_lock, lock);
 }
 
+static __always_inline void __raw_spin_lock_flags(struct raw_spinlock *lock,
+                                                 unsigned long flags)
+{
+       PVOP_VCALL2(pv_lock_ops.spin_lock_flags, lock, flags);
+}
+
 static __always_inline int __raw_spin_trylock(struct raw_spinlock *lock)
 {
        return PVOP_CALL1(int, pv_lock_ops.spin_trylock, lock);
index c7d35464a4bb2253c03eeafe6b6bc493419c83b1..ee7cbb30773ae05709518f0cc63307162407c90c 100644 (file)
@@ -586,41 +586,6 @@ static inline void clear_in_cr4(unsigned long mask)
        write_cr4(cr4);
 }
 
-struct microcode_header {
-       unsigned int            hdrver;
-       unsigned int            rev;
-       unsigned int            date;
-       unsigned int            sig;
-       unsigned int            cksum;
-       unsigned int            ldrver;
-       unsigned int            pf;
-       unsigned int            datasize;
-       unsigned int            totalsize;
-       unsigned int            reserved[3];
-};
-
-struct microcode {
-       struct microcode_header hdr;
-       unsigned int            bits[0];
-};
-
-typedef struct microcode       microcode_t;
-typedef struct microcode_header        microcode_header_t;
-
-/* microcode format is extended from prescott processors */
-struct extended_signature {
-       unsigned int            sig;
-       unsigned int            pf;
-       unsigned int            cksum;
-};
-
-struct extended_sigtable {
-       unsigned int            count;
-       unsigned int            cksum;
-       unsigned int            reserved[3];
-       struct extended_signature sigs[0];
-};
-
 typedef struct {
        unsigned long           seg;
 } mm_segment_t;
index d64a6109716531261d43bb1f80dc37060c6067dc..ac578f11c1c563e03cb31bf3e1a61fdfe2288c34 100644 (file)
@@ -177,11 +177,11 @@ convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
 
 #ifdef CONFIG_X86_32
 extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
-                        int error_code);
-#else
-void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+                        int error_code, int si_code);
 #endif
 
+void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
+
 extern long syscall_trace_enter(struct pt_regs *);
 extern void syscall_trace_leave(struct pt_regs *);
 
index 29324c103341d4f2653c36d561f665eca7e5094b..6df2615f9138728cfd29ea2ac46a0194c1fd1555 100644 (file)
@@ -50,12 +50,16 @@ extern struct {
 struct smp_ops {
        void (*smp_prepare_boot_cpu)(void);
        void (*smp_prepare_cpus)(unsigned max_cpus);
-       int (*cpu_up)(unsigned cpu);
        void (*smp_cpus_done)(unsigned max_cpus);
 
        void (*smp_send_stop)(void);
        void (*smp_send_reschedule)(int cpu);
 
+       int (*cpu_up)(unsigned cpu);
+       int (*cpu_disable)(void);
+       void (*cpu_die)(unsigned int cpu);
+       void (*play_dead)(void);
+
        void (*send_call_func_ipi)(cpumask_t mask);
        void (*send_call_func_single_ipi)(int cpu);
 };
@@ -94,6 +98,21 @@ static inline int __cpu_up(unsigned int cpu)
        return smp_ops.cpu_up(cpu);
 }
 
+static inline int __cpu_disable(void)
+{
+       return smp_ops.cpu_disable();
+}
+
+static inline void __cpu_die(unsigned int cpu)
+{
+       smp_ops.cpu_die(cpu);
+}
+
+static inline void play_dead(void)
+{
+       smp_ops.play_dead();
+}
+
 static inline void smp_send_reschedule(int cpu)
 {
        smp_ops.smp_send_reschedule(cpu);
@@ -109,16 +128,19 @@ static inline void arch_send_call_function_ipi(cpumask_t mask)
        smp_ops.send_call_func_ipi(mask);
 }
 
+void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
 void native_smp_cpus_done(unsigned int max_cpus);
 int native_cpu_up(unsigned int cpunum);
+int native_cpu_disable(void);
+void native_cpu_die(unsigned int cpu);
+void native_play_dead(void);
+void play_dead_common(void);
+
 void native_send_call_func_ipi(cpumask_t mask);
 void native_send_call_func_single_ipi(int cpu);
 
-extern int __cpu_disable(void);
-extern void __cpu_die(unsigned int cpu);
-
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)   per_cpu(x86_cpu_to_apicid, cpu)
 
@@ -205,9 +227,5 @@ static inline int hard_smp_processor_id(void)
 
 #endif /* CONFIG_X86_LOCAL_APIC */
 
-#ifdef CONFIG_HOTPLUG_CPU
-extern void cpu_uninit(void);
-#endif
-
 #endif /* __ASSEMBLY__ */
 #endif /* ASM_X86__SMP_H */
index 93adae338ac64625ab1c1ec63634edd8c3d8dcd3..157ff7fab97aba964216472e6f67aac147e3b901 100644 (file)
 
 #ifdef CONFIG_X86_32
 # define LOCK_PTR_REG "a"
+# define REG_PTR_MODE "k"
 #else
 # define LOCK_PTR_REG "D"
+# define REG_PTR_MODE "q"
 #endif
 
 #if defined(CONFIG_X86_32) && \
  * much between them in performance though, especially as locks are out of line.
  */
 #if (NR_CPUS < 256)
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 8) & 0xff) != (tmp & 0xff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 8) - tmp) & 0xff) > 1;
-}
+#define TICKET_SHIFT 8
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
@@ -89,19 +79,17 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 
 static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
 {
-       int tmp;
-       short new;
+       int tmp, new;
 
-       asm volatile("movw %2,%w0\n\t"
+       asm volatile("movzwl %2, %0\n\t"
                     "cmpb %h0,%b0\n\t"
+                    "leal 0x100(%" REG_PTR_MODE "0), %1\n\t"
                     "jne 1f\n\t"
-                    "movw %w0,%w1\n\t"
-                    "incb %h1\n\t"
                     LOCK_PREFIX "cmpxchgw %w1,%2\n\t"
                     "1:"
                     "sete %b1\n\t"
                     "movzbl %b1,%0\n\t"
-                    : "=&a" (tmp), "=Q" (new), "+m" (lock->slock)
+                    : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
                     :
                     : "memory", "cc");
 
@@ -116,19 +104,7 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
                     : "memory", "cc");
 }
 #else
-static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 16) & 0xffff) != (tmp & 0xffff));
-}
-
-static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
-{
-       int tmp = ACCESS_ONCE(lock->slock);
-
-       return (((tmp >> 16) - tmp) & 0xffff) > 1;
-}
+#define TICKET_SHIFT 16
 
 static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
 {
@@ -146,7 +122,7 @@ static __always_inline void __ticket_spin_lock(raw_spinlock_t *lock)
                     /* don't need lfence here, because loads are in-order */
                     "jmp 1b\n"
                     "2:"
-                    : "+Q" (inc), "+m" (lock->slock), "=r" (tmp)
+                    : "+r" (inc), "+m" (lock->slock), "=&r" (tmp)
                     :
                     : "memory", "cc");
 }
@@ -160,13 +136,13 @@ static __always_inline int __ticket_spin_trylock(raw_spinlock_t *lock)
                     "movl %0,%1\n\t"
                     "roll $16, %0\n\t"
                     "cmpl %0,%1\n\t"
+                    "leal 0x00010000(%" REG_PTR_MODE "0), %1\n\t"
                     "jne 1f\n\t"
-                    "addl $0x00010000, %1\n\t"
                     LOCK_PREFIX "cmpxchgl %1,%2\n\t"
                     "1:"
                     "sete %b1\n\t"
                     "movzbl %b1,%0\n\t"
-                    : "=&a" (tmp), "=r" (new), "+m" (lock->slock)
+                    : "=&a" (tmp), "=&q" (new), "+m" (lock->slock)
                     :
                     : "memory", "cc");
 
@@ -182,7 +158,19 @@ static __always_inline void __ticket_spin_unlock(raw_spinlock_t *lock)
 }
 #endif
 
-#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
+static inline int __ticket_spin_is_locked(raw_spinlock_t *lock)
+{
+       int tmp = ACCESS_ONCE(lock->slock);
+
+       return !!(((tmp >> TICKET_SHIFT) ^ tmp) & ((1 << TICKET_SHIFT) - 1));
+}
+
+static inline int __ticket_spin_is_contended(raw_spinlock_t *lock)
+{
+       int tmp = ACCESS_ONCE(lock->slock);
+
+       return (((tmp >> TICKET_SHIFT) - tmp) & ((1 << TICKET_SHIFT) - 1)) > 1;
+}
 
 #ifdef CONFIG_PARAVIRT
 /*
@@ -272,6 +260,13 @@ static __always_inline void __raw_spin_unlock(raw_spinlock_t *lock)
 {
        __ticket_spin_unlock(lock);
 }
+
+static __always_inline void __raw_spin_lock_flags(raw_spinlock_t *lock,
+                                                 unsigned long flags)
+{
+       __raw_spin_lock(lock);
+}
+
 #endif /* CONFIG_PARAVIRT */
 
 static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
index ef68b76dc3c5c32f0ee2f24a1ecfec5725bba003..3cdd08b5bdb741d0dc55352295a6efa0058bb944 100644 (file)
@@ -119,6 +119,10 @@ static inline void native_flush_tlb_others(const cpumask_t *cpumask,
 {
 }
 
+static inline void reset_lazy_tlbstate(void)
+{
+}
+
 #else  /* SMP */
 
 #include <asm/smp.h>
@@ -151,6 +155,12 @@ struct tlb_state {
        char __cacheline_padding[L1_CACHE_BYTES-8];
 };
 DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
+
+void reset_lazy_tlbstate(void);
+#else
+static inline void reset_lazy_tlbstate(void)
+{
+}
 #endif
 
 #endif /* SMP */
index 2ccebc6fb0b0143c9605ab548662718dacb8b97d..7a692baa51ae1548cf255c514ec4521a77a815b3 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef ASM_X86__TRAPS_H
 #define ASM_X86__TRAPS_H
 
+#include <asm/debugreg.h>
+
 /* Common in X86_32 and X86_64 */
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
@@ -36,6 +38,16 @@ void do_invalid_op(struct pt_regs *, long);
 void do_general_protection(struct pt_regs *, long);
 void do_nmi(struct pt_regs *, long);
 
+static inline int get_si_code(unsigned long condition)
+{
+       if (condition & DR_STEP)
+               return TRAP_TRACE;
+       else if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3))
+               return TRAP_HWBKPT;
+       else
+               return TRAP_BRKPT;
+}
+
 extern int panic_on_unrecovered_nmi;
 extern int kstack_depth_to_print;
 
index 0ef3a88b869df8c67ec6ec64021b664d5aec71a7..445a247595606919e331875acfc34903eff380a9 100644 (file)
@@ -54,7 +54,6 @@
 /* arch/i386/kernel/setup.c */
 extern struct shared_info *HYPERVISOR_shared_info;
 extern struct start_info *xen_start_info;
-#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
 
 /* arch/i386/mach-xen/evtchn.c */
 /* Force a proper event-channel callback from Xen. */
@@ -67,6 +66,17 @@ u64 jiffies_to_st(unsigned long jiffies);
 #define MULTI_UVMFLAGS_INDEX 3
 #define MULTI_UVMDOMID_INDEX 4
 
-#define is_running_on_xen()    (xen_start_info ? 1 : 0)
+enum xen_domain_type {
+       XEN_NATIVE,
+       XEN_PV_DOMAIN,
+       XEN_HVM_DOMAIN,
+};
+
+extern enum xen_domain_type xen_domain_type;
+
+#define xen_domain()           (xen_domain_type != XEN_NATIVE)
+#define xen_pv_domain()                (xen_domain_type == XEN_PV_DOMAIN)
+#define xen_initial_domain()   (xen_pv_domain() && xen_start_info->flags & SIF_INITDOMAIN)
+#define xen_hvm_domain()       (xen_domain_type == XEN_HVM_DOMAIN)
 
 #endif /* ASM_X86__XEN__HYPERVISOR_H */
index edc3dac3f02f446802136b6ad65bbc39cbd6996a..0b61ca41a0445009ee757680aa31fa2320e144f2 100644 (file)
@@ -360,6 +360,7 @@ typedef struct elf64_shdr {
 #define NT_PPC_SPE     0x101           /* PowerPC SPE/EVR registers */
 #define NT_PPC_VSX     0x102           /* PowerPC VSX registers */
 #define NT_386_TLS     0x200           /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM  0x201           /* x86 io permission bitmap (1=deny) */
 
 
 /* Note header in a PT_NOTE section */
index 2651f805ba6d771b9ec1f26078609aebdb198853..75d81f157d2edbd7a8aec39ce3cb7cc3bd69a758 100644 (file)
@@ -182,7 +182,7 @@ extern int vsscanf(const char *, const char *, va_list)
 
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
-extern unsigned long long memparse(char *ptr, char **retptr);
+extern unsigned long long memparse(const char *ptr, char **retptr);
 
 extern int core_kernel_text(unsigned long addr);
 extern int __kernel_text_address(unsigned long addr);
index c45c962d1cc527e82aa37f8c76385d87fc236c4a..1b70e35a71e378808454a60429c478c20200fe48 100644 (file)
@@ -299,6 +299,7 @@ extern void key_init(void);
 #define key_validate(k)                        0
 #define key_serial(k)                  0
 #define key_get(k)                     ({ NULL; })
+#define key_revoke(k)                  do { } while(0)
 #define key_put(k)                     do { } while(0)
 #define key_ref_put(k)                 do { } while(0)
 #define make_key_ref(k, p)                     ({ NULL; })
index 72a15dc26bbf399bb891f01f740283e723929b33..c61ba10768ea48d6691cd58678476f35c1c878f1 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/gfp.h>
 #include <linux/list.h>
+#include <linux/mmdebug.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
 #include <linux/prio_tree.h>
@@ -219,12 +220,6 @@ struct inode;
  */
 #include <linux/page-flags.h>
 
-#ifdef CONFIG_DEBUG_VM
-#define VM_BUG_ON(cond) BUG_ON(cond)
-#else
-#define VM_BUG_ON(condition) do { } while(0)
-#endif
-
 /*
  * Methods to modify the page usage count.
  *
@@ -919,7 +914,7 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
 }
 #endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * We tuck a spinlock to guard each pagetable page into its struct page,
  * at page->private, with BUILD_BUG_ON to make sure that this will not
@@ -932,14 +927,14 @@ static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long a
 } while (0)
 #define pte_lock_deinit(page)  ((page)->mapping = NULL)
 #define pte_lockptr(mm, pmd)   ({(void)(mm); __pte_lockptr(pmd_page(*(pmd)));})
-#else
+#else  /* !USE_SPLIT_PTLOCKS */
 /*
  * We use mm->page_table_lock to guard all pagetable pages of the mm.
  */
 #define pte_lock_init(page)    do {} while (0)
 #define pte_lock_deinit(page)  do {} while (0)
 #define pte_lockptr(mm, pmd)   ({(void)(pmd); &(mm)->page_table_lock;})
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* USE_SPLIT_PTLOCKS */
 
 static inline void pgtable_page_ctor(struct page *page)
 {
index bf334138c7c148da4c9ec7b409254045de0d327b..9d49fa36bbeff3237e2e0f4925a0ed3ac1ec1b29 100644 (file)
 
 struct address_space;
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#define USE_SPLIT_PTLOCKS      (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
+
+#if USE_SPLIT_PTLOCKS
 typedef atomic_long_t mm_counter_t;
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 typedef unsigned long mm_counter_t;
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 /*
  * Each physical page in the system has a struct page associated with
@@ -65,7 +67,7 @@ struct page {
                                                 * see PAGE_MAPPING_ANON below.
                                                 */
            };
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
            spinlock_t ptl;
 #endif
            struct kmem_cache *slab;    /* SLUB: Pointer to slab */
index 9c288c9098783cfc3ef1b4d6357081b7d3f44849..bde891f645913cc2f9a0b5cc4b0447fa8d1f1abe 100644 (file)
@@ -65,7 +65,7 @@ struct mmc_host_ops {
         *   -ENOSYS when not supported (equal to NULL callback)
         *   or a negative errno value when something bad happened
         *
-        * Return values for the get_ro callback should be:
+        * Return values for the get_cd callback should be:
         *   0 for a absent card
         *   1 for a present card
         *   -ENOSYS when not supported (equal to NULL callback)
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
new file mode 100644 (file)
index 0000000..8a55098
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef LINUX_MM_DEBUG_H
+#define LINUX_MM_DEBUG_H 1
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_DEBUG_VM
+#define VM_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VM_BUG_ON(cond) do { } while (0)
+#endif
+
+#ifdef CONFIG_DEBUG_VIRTUAL
+#define VIRTUAL_BUG_ON(cond) BUG_ON(cond)
+#else
+#define VIRTUAL_BUG_ON(cond) do { } while (0)
+#endif
+
+#endif
index e8c7c21ceb1fe12b1f9e29a8868c59f8c1266874..6fc961459b4a277d52d12d5f65da2eddaa0bc4ef 100644 (file)
 /*
  * M48T59 Register Offset
  */
-#define M48T59_YEAR            0x1fff
-#define M48T59_MONTH           0x1ffe
-#define M48T59_MDAY            0x1ffd  /* Day of Month */
-#define M48T59_WDAY            0x1ffc  /* Day of Week */
+#define M48T59_YEAR            0xf
+#define M48T59_MONTH           0xe
+#define M48T59_MDAY            0xd     /* Day of Month */
+#define M48T59_WDAY            0xc     /* Day of Week */
 #define M48T59_WDAY_CB                 0x20    /* Century Bit */
 #define M48T59_WDAY_CEB                        0x10    /* Century Enable Bit */
-#define M48T59_HOUR            0x1ffb
-#define M48T59_MIN             0x1ffa
-#define M48T59_SEC             0x1ff9
-#define M48T59_CNTL            0x1ff8
+#define M48T59_HOUR            0xb
+#define M48T59_MIN             0xa
+#define M48T59_SEC             0x9
+#define M48T59_CNTL            0x8
 #define M48T59_CNTL_READ               0x40
 #define M48T59_CNTL_WRITE              0x80
-#define M48T59_WATCHDOG                0x1ff7
-#define M48T59_INTR            0x1ff6
+#define M48T59_WATCHDOG                0x7
+#define M48T59_INTR            0x6
 #define M48T59_INTR_AFE                        0x80    /* Alarm Interrupt Enable */
 #define M48T59_INTR_ABE                        0x20
-#define M48T59_ALARM_DATE      0x1ff5
-#define M48T59_ALARM_HOUR      0x1ff4
-#define M48T59_ALARM_MIN       0x1ff3
-#define M48T59_ALARM_SEC       0x1ff2
-#define M48T59_UNUSED          0x1ff1
-#define M48T59_FLAGS           0x1ff0
+#define M48T59_ALARM_DATE      0x5
+#define M48T59_ALARM_HOUR      0x4
+#define M48T59_ALARM_MIN       0x3
+#define M48T59_ALARM_SEC       0x2
+#define M48T59_UNUSED          0x1
+#define M48T59_FLAGS           0x0
 #define M48T59_FLAGS_WDT               0x80    /* watchdog timer expired */
 #define M48T59_FLAGS_AF                        0x40    /* alarm */
 #define M48T59_FLAGS_BF                        0x10    /* low battery */
 
-#define M48T59_NVRAM_SIZE      0x1ff0
+#define M48T59RTC_TYPE_M48T59  0 /* to keep compatibility */
+#define M48T59RTC_TYPE_M48T02  1
+#define M48T59RTC_TYPE_M48T08  2
 
 struct m48t59_plat_data {
-       /* The method to access M48T59 registers,
-        * NOTE: The 'ofs' should be 0x00~0x1fff
-        */
+       /* The method to access M48T59 registers */
        void (*write_byte)(struct device *dev, u32 ofs, u8 val);
        unsigned char (*read_byte)(struct device *dev, u32 ofs);
+
+       int type; /* RTC model */
+
+       /* ioaddr mapped externally */
+       void __iomem *ioaddr;
+       /* offset to RTC registers, automatically set according to the type */
+       unsigned int offset;
 };
 
 #endif /* _LINUX_RTC_M48T59_H_ */
index 5d0819ee442a471e840b37a5ea1c35ee13030d25..c226c7b82946ce1d830853c4fd3b9bad3d92fa0d 100644 (file)
@@ -352,7 +352,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr,
 extern void arch_unmap_area(struct mm_struct *, unsigned long);
 extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+#if USE_SPLIT_PTLOCKS
 /*
  * The mm counters are not protected by its page_table_lock,
  * so must be incremented atomically.
@@ -363,7 +363,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 #define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member)
 #define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member)
 
-#else  /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#else  /* !USE_SPLIT_PTLOCKS */
 /*
  * The mm counters are protected by its page_table_lock,
  * so can be incremented directly.
@@ -374,7 +374,7 @@ extern void arch_unmap_area_topdown(struct mm_struct *, unsigned long);
 #define inc_mm_counter(mm, member) (mm)->_##member++
 #define dec_mm_counter(mm, member) (mm)->_##member--
 
-#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */
+#endif /* !USE_SPLIT_PTLOCKS */
 
 #define get_mm_rss(mm)                                 \
        (get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss))
diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h
new file mode 100644 (file)
index 0000000..5b88e36
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_USB_EHCI_DEF_H
+#define __LINUX_USB_EHCI_DEF_H
+
+/* EHCI register interface, corresponds to EHCI Revision 0.95 specification */
+
+/* Section 2.2 Host Controller Capability Registers */
+struct ehci_caps {
+       /* these fields are specified as 8 and 16 bit registers,
+        * but some hosts can't perform 8 or 16 bit PCI accesses.
+        */
+       u32             hc_capbase;
+#define HC_LENGTH(p)           (((p)>>00)&0x00ff)      /* bits 7:0 */
+#define HC_VERSION(p)          (((p)>>16)&0xffff)      /* bits 31:16 */
+       u32             hcs_params;     /* HCSPARAMS - offset 0x4 */
+#define HCS_DEBUG_PORT(p)      (((p)>>20)&0xf) /* bits 23:20, debug port? */
+#define HCS_INDICATOR(p)       ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_N_CC(p)            (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
+#define HCS_N_PCC(p)           (((p)>>8)&0xf)  /* bits 11:8, ports per CC */
+#define HCS_PORTROUTED(p)      ((p)&(1 << 7))  /* true: port routing */
+#define HCS_PPC(p)             ((p)&(1 << 4))  /* true: port power control */
+#define HCS_N_PORTS(p)         (((p)>>0)&0xf)  /* bits 3:0, ports on HC */
+
+       u32             hcc_params;      /* HCCPARAMS - offset 0x8 */
+#define HCC_EXT_CAPS(p)                (((p)>>8)&0xff) /* for pci extended caps */
+#define HCC_ISOC_CACHE(p)       ((p)&(1 << 7))  /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p)       (((p)>>4)&0x7)  /* bits 6:4, uframes cached */
+#define HCC_CANPARK(p)         ((p)&(1 << 2))  /* true: can park on async qh */
+#define HCC_PGM_FRAMELISTLEN(p) ((p)&(1 << 1))  /* true: periodic_size changes*/
+#define HCC_64BIT_ADDR(p)       ((p)&(1))       /* true: can use 64-bit addr */
+       u8              portroute [8];   /* nibbles for routing - offset 0xC */
+} __attribute__ ((packed));
+
+
+/* Section 2.3 Host Controller Operational Registers */
+struct ehci_regs {
+
+       /* USBCMD: offset 0x00 */
+       u32             command;
+/* 23:16 is r/w intr rate, in microframes; default "8" == 1/msec */
+#define CMD_PARK       (1<<11)         /* enable "park" on async qh */
+#define CMD_PARK_CNT(c)        (((c)>>8)&3)    /* how many transfers to park for */
+#define CMD_LRESET     (1<<7)          /* partial reset (no ports, etc) */
+#define CMD_IAAD       (1<<6)          /* "doorbell" interrupt async advance */
+#define CMD_ASE                (1<<5)          /* async schedule enable */
+#define CMD_PSE                (1<<4)          /* periodic schedule enable */
+/* 3:2 is periodic frame list size */
+#define CMD_RESET      (1<<1)          /* reset HC not bus */
+#define CMD_RUN                (1<<0)          /* start/stop HC */
+
+       /* USBSTS: offset 0x04 */
+       u32             status;
+#define STS_ASS                (1<<15)         /* Async Schedule Status */
+#define STS_PSS                (1<<14)         /* Periodic Schedule Status */
+#define STS_RECL       (1<<13)         /* Reclamation */
+#define STS_HALT       (1<<12)         /* Not running (any reason) */
+/* some bits reserved */
+       /* these STS_* flags are also intr_enable bits (USBINTR) */
+#define STS_IAA                (1<<5)          /* Interrupted on async advance */
+#define STS_FATAL      (1<<4)          /* such as some PCI access errors */
+#define STS_FLR                (1<<3)          /* frame list rolled over */
+#define STS_PCD                (1<<2)          /* port change detect */
+#define STS_ERR                (1<<1)          /* "error" completion (overflow, ...) */
+#define STS_INT                (1<<0)          /* "normal" completion (short, ...) */
+
+       /* USBINTR: offset 0x08 */
+       u32             intr_enable;
+
+       /* FRINDEX: offset 0x0C */
+       u32             frame_index;    /* current microframe number */
+       /* CTRLDSSEGMENT: offset 0x10 */
+       u32             segment;        /* address bits 63:32 if needed */
+       /* PERIODICLISTBASE: offset 0x14 */
+       u32             frame_list;     /* points to periodic list */
+       /* ASYNCLISTADDR: offset 0x18 */
+       u32             async_next;     /* address of next async queue head */
+
+       u32             reserved [9];
+
+       /* CONFIGFLAG: offset 0x40 */
+       u32             configured_flag;
+#define FLAG_CF                (1<<0)          /* true: we'll support "high speed" */
+
+       /* PORTSC: offset 0x44 */
+       u32             port_status [0];        /* up to N_PORTS */
+/* 31:23 reserved */
+#define PORT_WKOC_E    (1<<22)         /* wake on overcurrent (enable) */
+#define PORT_WKDISC_E  (1<<21)         /* wake on disconnect (enable) */
+#define PORT_WKCONN_E  (1<<20)         /* wake on connect (enable) */
+/* 19:16 for port testing */
+#define PORT_LED_OFF   (0<<14)
+#define PORT_LED_AMBER (1<<14)
+#define PORT_LED_GREEN (2<<14)
+#define PORT_LED_MASK  (3<<14)
+#define PORT_OWNER     (1<<13)         /* true: companion hc owns this port */
+#define PORT_POWER     (1<<12)         /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x)&(3<<10)) == (1<<10))       /* USB 1.1 device */
+/* 11:10 for detecting lowspeed devices (reset vs release ownership) */
+/* 9 reserved */
+#define PORT_RESET     (1<<8)          /* reset port */
+#define PORT_SUSPEND   (1<<7)          /* suspend port */
+#define PORT_RESUME    (1<<6)          /* resume it */
+#define PORT_OCC       (1<<5)          /* over current change */
+#define PORT_OC                (1<<4)          /* over current active */
+#define PORT_PEC       (1<<3)          /* port enable change */
+#define PORT_PE                (1<<2)          /* port enable */
+#define PORT_CSC       (1<<1)          /* connect status change */
+#define PORT_CONNECT   (1<<0)          /* device connected */
+#define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
+} __attribute__ ((packed));
+
+#define USBMODE                0x68            /* USB Device mode */
+#define USBMODE_SDIS   (1<<3)          /* Stream disable */
+#define USBMODE_BE     (1<<2)          /* BE/LE endianness select */
+#define USBMODE_CM_HC  (3<<0)          /* host controller mode */
+#define USBMODE_CM_IDLE        (0<<0)          /* idle state */
+
+/* Appendix C, Debug port ... intended for use with special "debug devices"
+ * that can help if there's no serial console.  (nonstandard enumeration.)
+ */
+struct ehci_dbg_port {
+       u32     control;
+#define DBGP_OWNER     (1<<30)
+#define DBGP_ENABLED   (1<<28)
+#define DBGP_DONE      (1<<16)
+#define DBGP_INUSE     (1<<10)
+#define DBGP_ERRCODE(x)        (((x)>>7)&0x07)
+#      define DBGP_ERR_BAD     1
+#      define DBGP_ERR_SIGNAL  2
+#define DBGP_ERROR     (1<<6)
+#define DBGP_GO                (1<<5)
+#define DBGP_OUT       (1<<4)
+#define DBGP_LEN(x)    (((x)>>0)&0x0f)
+       u32     pids;
+#define DBGP_PID_GET(x)                (((x)>>16)&0xff)
+#define DBGP_PID_SET(data, tok)        (((data)<<8)|(tok))
+       u32     data03;
+       u32     data47;
+       u32     address;
+#define DBGP_EPADDR(dev, ep)   (((dev)<<8)|(ep))
+} __attribute__ ((packed));
+
+#endif /* __LINUX_USB_EHCI_DEF_H */
index e5eec5f7350213c8fda3d6f76c3f0a725c22b1e0..35424a971b7a68d89ab75630eac1e197ebae8619 100644 (file)
@@ -43,9 +43,6 @@
 #ifdef CONFIG_PCI
 struct pci_dev;
 #endif
-#ifdef CONFIG_SBUS
-struct sbus_dev;
-#endif
 
 /* device allocation stuff */
 
index d787a6b4a10123006f1384ffc61153ec9c9a733c..7ccce94a5255edc09b28413ede92178c10230055 100644 (file)
@@ -37,7 +37,6 @@ struct snd_dma_device {
 #ifndef snd_dma_pci_data
 #define snd_dma_pci_data(pci)  (&(pci)->dev)
 #define snd_dma_isa_data()     NULL
-#define snd_dma_sbus_data(sbus)        ((struct device *)(sbus))
 #define snd_dma_continuous_data(x)     ((struct device *)(unsigned long)(x))
 #endif
 
@@ -49,7 +48,6 @@ struct snd_dma_device {
 #define SNDRV_DMA_TYPE_CONTINUOUS      1       /* continuous no-DMA memory */
 #define SNDRV_DMA_TYPE_DEV             2       /* generic device continuous */
 #define SNDRV_DMA_TYPE_DEV_SG          3       /* generic device SG-buffer */
-#define SNDRV_DMA_TYPE_SBUS            4       /* SBUS continuous */
 
 /*
  * info for buffer allocation
diff --git a/include/xen/balloon.h b/include/xen/balloon.h
deleted file mode 100644 (file)
index fe43b0f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************************************
- * balloon.h
- *
- * Xen balloon driver - enables returning/claiming memory to/from Xen.
- *
- * Copyright (c) 2003, B Dragovic
- * Copyright (c) 2003-2004, M Williamson, K Fraser
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation; or, when distributed
- * separately from the Linux kernel or incorporated into other
- * software packages, subject to the following license:
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this source file (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use, copy, modify,
- * merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __XEN_BALLOON_H__
-#define __XEN_BALLOON_H__
-
-#include <linux/spinlock.h>
-
-#if 0
-/*
- * Inform the balloon driver that it should allow some slop for device-driver
- * memory activities.
- */
-void balloon_update_driver_allowance(long delta);
-
-/* Allocate/free a set of empty pages in low memory (i.e., no RAM mapped). */
-struct page **alloc_empty_pages_and_pagevec(int nr_pages);
-void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages);
-
-void balloon_release_driver_page(struct page *page);
-
-/*
- * Prevent the balloon driver from changing the memory reservation during
- * a driver critical region.
- */
-extern spinlock_t balloon_lock;
-#define balloon_lock(__flags)   spin_lock_irqsave(&balloon_lock, __flags)
-#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
-#endif
-
-#endif /* __XEN_BALLOON_H__ */
index 4680ff3fbc91c569990e2c48bec8183ffe7888f3..0d5f1adc0363e9e125cb8786ca96b0917440b6b5 100644 (file)
@@ -46,6 +46,8 @@ extern void xen_irq_resume(void);
 
 /* Clear an irq's pending state, in preparation for polling on it */
 void xen_clear_irq_pending(int irq);
+void xen_set_irq_pending(int irq);
+bool xen_test_irq_pending(int irq);
 
 /* Poll waiting for an irq to become pending.  In the usual case, the
    irq will be disabled so it won't deliver an interrupt. */
index 50ec0886fa3d355d696e9992a9057ce11a721525..1bf369bd44234e829905d9a565577537c040c846 100644 (file)
@@ -118,10 +118,8 @@ extern char modprobe_path[];
 extern int sg_big_buff;
 #endif
 
-#ifdef __sparc__
-extern char reboot_command [];
-extern int stop_a_enabled;
-extern int scons_pwroff;
+#ifdef CONFIG_SPARC
+#include <asm/system.h>
 #endif
 
 #ifdef __hppa__
@@ -415,7 +413,7 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
        {
                .ctl_name       = KERN_SPARC_REBOOT,
                .procname       = "reboot-cmd",
index ce697e0b319ea08e8b8127197dd87becd9f0ef99..aa81d2848448db8f007194cc086804dcffe2623e 100644 (file)
@@ -495,6 +495,15 @@ config DEBUG_VM
 
          If unsure, say N.
 
+config DEBUG_VIRTUAL
+       bool "Debug VM translations"
+       depends on DEBUG_KERNEL && X86
+       help
+         Enable some costly sanity checks in virtual to page code. This can
+         catch mistakes with virt_to_page() and friends.
+
+         If unsure, say N.
+
 config DEBUG_WRITECOUNT
        bool "Debug filesystem writers count"
        depends on DEBUG_KERNEL
index 5ba8a942a478fe8d75f895ea7f26f876810772a5..f5f3ad8b62ff9844739fcdedde9389e6869e0cfc 100644 (file)
@@ -126,7 +126,7 @@ char *get_options(const char *str, int nints, int *ints)
  *     megabyte, or one gigabyte, respectively.
  */
 
-unsigned long long memparse(char *ptr, char **retptr)
+unsigned long long memparse(const char *ptr, char **retptr)
 {
        char *endptr;   /* local pointer to end of parsed string */
 
index 85b9a0d2c877402ee6c06e97fd9084919ed8485b..bba06c41fc59ed10be118f7af24ecfa71d023c33 100644 (file)
@@ -180,6 +180,13 @@ struct page *vmalloc_to_page(const void *vmalloc_addr)
        pmd_t *pmd;
        pte_t *ptep, pte;
 
+       /*
+        * XXX we might need to change this if we add VIRTUAL_BUG_ON for
+        * architectures that do not vmalloc module space
+        */
+       VIRTUAL_BUG_ON(!is_vmalloc_addr(vmalloc_addr) &&
+                       !is_module_address(addr));
+
        if (!pgd_none(*pgd)) {
                pud = pud_offset(pgd, addr);
                if (!pud_none(*pud)) {
index 05ebce2881efc30924c95a4ae56fbd26ab817eb1..85c487b8572b726a365e869a92e8ad00669d76b7 100644 (file)
@@ -1345,7 +1345,7 @@ out:
 static void ipgre_netlink_parms(struct nlattr *data[],
                                struct ip_tunnel_parm *parms)
 {
-       memset(parms, 0, sizeof(parms));
+       memset(parms, 0, sizeof(*parms));
 
        parms->iph.protocol = IPPROTO_GRE;
 
index de6004de80bcb4b72506c5409e0744b9544c9b84..05048e4032661d7b96477db4b9ed6501713797cd 100644 (file)
@@ -2,8 +2,8 @@
 # IP Virtual Server configuration
 #
 menuconfig IP_VS
-       tristate "IP virtual server support (EXPERIMENTAL)"
-       depends on NETFILTER
+       tristate "IP virtual server support"
+       depends on NET && INET && NETFILTER
        ---help---
          IP Virtual Server support will let you build a high-performance
          virtual server based on cluster of two or more real servers. This
index d64e6badc9427ed9d6c8a2d47652d5ecab693293..982dcae7bbe241caff6c4a3f54657c8cb6b3152b 100644 (file)
@@ -105,12 +105,12 @@ as-instr = $(call try-run,\
 # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
 
 cc-option = $(call try-run,\
-       $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",$(1),$(2))
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
 
 # cc-option-yn
 # Usage: flag := $(call cc-option-yn,-march=winchip-c6)
 cc-option-yn = $(call try-run,\
-       $(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
 
 # cc-option-align
 # Prefix align with either -falign or -malign
index a7b46ec72f3231191cb6f81d7c816f6b011bc696..1b3534d67686d407992b7f712306c43d87e29863 100644 (file)
@@ -33,9 +33,6 @@
 #include <linux/moduleparam.h>
 #include <linux/mutex.h>
 #include <sound/memalloc.h>
-#ifdef CONFIG_SBUS
-#include <asm/sbus.h>
-#endif
 
 
 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>, Jaroslav Kysela <perex@perex.cz>");
@@ -162,39 +159,6 @@ static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr,
 }
 #endif /* CONFIG_HAS_DMA */
 
-#ifdef CONFIG_SBUS
-
-static void *snd_malloc_sbus_pages(struct device *dev, size_t size,
-                                  dma_addr_t *dma_addr)
-{
-       struct sbus_dev *sdev = (struct sbus_dev *)dev;
-       int pg;
-       void *res;
-
-       if (WARN_ON(!dma_addr))
-               return NULL;
-       pg = get_order(size);
-       res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr);
-       if (res != NULL)
-               inc_snd_pages(pg);
-       return res;
-}
-
-static void snd_free_sbus_pages(struct device *dev, size_t size,
-                               void *ptr, dma_addr_t dma_addr)
-{
-       struct sbus_dev *sdev = (struct sbus_dev *)dev;
-       int pg;
-
-       if (ptr == NULL)
-               return;
-       pg = get_order(size);
-       dec_snd_pages(pg);
-       sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr);
-}
-
-#endif /* CONFIG_SBUS */
-
 /*
  *
  *  ALSA generic memory management
@@ -231,11 +195,6 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
                dmab->area = snd_malloc_pages(size, (unsigned long)device);
                dmab->addr = 0;
                break;
-#ifdef CONFIG_SBUS
-       case SNDRV_DMA_TYPE_SBUS:
-               dmab->area = snd_malloc_sbus_pages(device, size, &dmab->addr);
-               break;
-#endif
 #ifdef CONFIG_HAS_DMA
        case SNDRV_DMA_TYPE_DEV:
                dmab->area = snd_malloc_dev_pages(device, size, &dmab->addr);
@@ -306,11 +265,6 @@ void snd_dma_free_pages(struct snd_dma_buffer *dmab)
        case SNDRV_DMA_TYPE_CONTINUOUS:
                snd_free_pages(dmab->area, dmab->bytes);
                break;
-#ifdef CONFIG_SBUS
-       case SNDRV_DMA_TYPE_SBUS:
-               snd_free_sbus_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
-               break;
-#endif
 #ifdef CONFIG_HAS_DMA
        case SNDRV_DMA_TYPE_DEV:
                snd_free_dev_pages(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
@@ -419,7 +373,7 @@ static int snd_mem_proc_read(struct seq_file *seq, void *offset)
        long pages = snd_allocated_pages >> (PAGE_SHIFT-12);
        struct snd_mem_list *mem;
        int devno;
-       static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG", "SBUS" };
+       static char *types[] = { "UNKNOWN", "CONT", "DEV", "DEV-SG" };
 
        mutex_lock(&list_mutex);
        seq_printf(seq, "pages  : %li bytes (%li pages per %likB)\n",
index 49acee0c4840216c968e1097ee9ed31e96464809..f87933e48812d8c7aba976d64fd9477912c85e41 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver for AMD7930 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/amd7930.c which is:
  * Copyright (C) 1996,1997 Thomas K. Dyas (tdyas@eden.rutgers.edu)
@@ -35,6 +35,8 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -44,7 +46,6 @@
 
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/sbus.h>
 #include <asm/prom.h>
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
@@ -335,8 +336,8 @@ struct snd_amd7930 {
        int                     pgain;
        int                     mgain;
 
+       struct of_device        *op;
        unsigned int            irq;
-       unsigned int            regs_size;
        struct snd_amd7930      *next;
 };
 
@@ -905,13 +906,16 @@ static int __devinit snd_amd7930_mixer(struct snd_amd7930 *amd)
 
 static int snd_amd7930_free(struct snd_amd7930 *amd)
 {
+       struct of_device *op = amd->op;
+
        amd7930_idle(amd);
 
        if (amd->irq)
                free_irq(amd->irq, amd);
 
        if (amd->regs)
-               sbus_iounmap(amd->regs, amd->regs_size);
+               of_iounmap(&op->resource[0], amd->regs,
+                          resource_size(&op->resource[0]));
 
        kfree(amd);
 
@@ -930,13 +934,12 @@ static struct snd_device_ops snd_amd7930_dev_ops = {
 };
 
 static int __devinit snd_amd7930_create(struct snd_card *card,
-                                       struct resource *rp,
-                                       unsigned int reg_size,
+                                       struct of_device *op,
                                        int irq, int dev,
                                        struct snd_amd7930 **ramd)
 {
-       unsigned long flags;
        struct snd_amd7930 *amd;
+       unsigned long flags;
        int err;
 
        *ramd = NULL;
@@ -946,9 +949,10 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
 
        spin_lock_init(&amd->lock);
        amd->card = card;
-       amd->regs_size = reg_size;
+       amd->op = op;
 
-       amd->regs = sbus_ioremap(rp, 0, amd->regs_size, "amd7930");
+       amd->regs = of_ioremap(&op->resource[0], 0,
+                              resource_size(&op->resource[0]), "amd7930");
        if (!amd->regs) {
                snd_printk("amd7930-%d: Unable to map chip registers.\n", dev);
                return -EIO;
@@ -997,12 +1001,15 @@ static int __devinit snd_amd7930_create(struct snd_card *card,
        return 0;
 }
 
-static int __devinit amd7930_attach_common(struct resource *rp, int irq)
+static int __devinit amd7930_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
+       struct resource *rp = &op->resource[0];
        static int dev_num;
        struct snd_card *card;
        struct snd_amd7930 *amd;
-       int err;
+       int err, irq;
+
+       irq = op->irqs[0];
 
        if (dev_num >= SNDRV_CARDS)
                return -ENODEV;
@@ -1023,8 +1030,7 @@ static int __devinit amd7930_attach_common(struct resource *rp, int irq)
                (unsigned long long)rp->start,
                irq);
 
-       if ((err = snd_amd7930_create(card, rp,
-                                     (rp->end - rp->start) + 1,
+       if ((err = snd_amd7930_create(card, op,
                                      irq, dev_num, &amd)) < 0)
                goto out_err;
 
@@ -1049,43 +1055,7 @@ out_err:
        return err;
 }
 
-static int __devinit amd7930_obio_attach(struct device_node *dp)
-{
-       const struct linux_prom_registers *regs;
-       const struct linux_prom_irqs *irqp;
-       struct resource res, *rp;
-       int len;
-
-       irqp = of_get_property(dp, "intr", &len);
-       if (!irqp) {
-               snd_printk("%s: Firmware node lacks IRQ property.\n",
-                          dp->full_name);
-               return -ENODEV;
-       }
-
-       regs = of_get_property(dp, "reg", &len);
-       if (!regs) {
-               snd_printk("%s: Firmware node lacks register property.\n",
-                          dp->full_name);
-               return -ENODEV;
-       }
-
-       rp = &res;
-       rp->start = regs->phys_addr;
-       rp->end = rp->start + regs->reg_size - 1;
-       rp->flags = IORESOURCE_IO | (regs->which_io & 0xff);
-
-       return amd7930_attach_common(rp, irqp->pri);
-}
-
-static int __devinit amd7930_sbus_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct sbus_dev *sdev = to_sbus_device(&dev->dev);
-
-       return amd7930_attach_common(&sdev->resource[0], sdev->irqs[0]);
-}
-
-static struct of_device_id amd7930_match[] = {
+static const struct of_device_id amd7930_match[] = {
        {
                .name = "audio",
        },
@@ -1100,20 +1070,7 @@ static struct of_platform_driver amd7930_sbus_driver = {
 
 static int __init amd7930_init(void)
 {
-       struct device_node *dp;
-
-       /* Try to find the sun4c "audio" node first. */
-       dp = of_find_node_by_path("/");
-       dp = dp->child;
-       while (dp) {
-               if (!strcmp(dp->name, "audio"))
-                       amd7930_obio_attach(dp);
-
-               dp = dp->sibling;
-       }
-
-       /* Probe each SBUS for amd7930 chips. */
-       return of_register_driver(&amd7930_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&amd7930_sbus_driver, &of_bus_type);
 }
 
 static void __exit amd7930_exit(void)
index 791d2fb821d17b40495a1cdfc127016752ba6790..d44bf98e965e6a5bd020f6d085dbcc2b763db670 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Driver for CS4231 sound chips found on Sparcs.
- * Copyright (C) 2002 David S. Miller <davem@redhat.com>
+ * Copyright (C) 2002, 2008 David S. Miller <davem@davemloft.net>
  *
  * Based entirely upon drivers/sbus/audio/cs4231.c which is:
  * Copyright (C) 1996, 1997, 1998 Derrick J Brashear (shadow@andrew.cmu.edu)
@@ -17,7 +17,8 @@
 #include <linux/moduleparam.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 
 #ifdef CONFIG_SBUS
 #define SBUS_SUPPORT
-#include <asm/sbus.h>
 #endif
 
 #if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
 #define EBUS_SUPPORT
 #include <linux/pci.h>
-#include <asm/ebus.h>
+#include <asm/ebus_dma.h>
 #endif
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;     /* Index 0-MAX */
@@ -70,8 +70,6 @@ struct cs4231_dma_control {
        int             (*request)(struct cs4231_dma_control *dma_cont,
                                   dma_addr_t bus_addr, size_t len);
        unsigned int    (*address)(struct cs4231_dma_control *dma_cont);
-       void            (*preallocate)(struct snd_cs4231 *chip,
-                                      struct snd_pcm *pcm);
 #ifdef EBUS_SUPPORT
        struct          ebus_dma_info   ebus_info;
 #endif
@@ -114,21 +112,12 @@ struct snd_cs4231 {
        struct mutex            mce_mutex;      /* mutex for mce register */
        struct mutex            open_mutex;     /* mutex for ALSA open/close */
 
-       union {
-#ifdef SBUS_SUPPORT
-               struct sbus_dev         *sdev;
-#endif
-#ifdef EBUS_SUPPORT
-               struct pci_dev          *pdev;
-#endif
-       } dev_u;
+       struct of_device        *op;
        unsigned int            irq[2];
        unsigned int            regs_size;
        struct snd_cs4231       *next;
 };
 
-static struct snd_cs4231 *cs4231_list;
-
 /* Eventually we can use sound/isa/cs423x/cs4231_lib.c directly, but for
  * now....  -DaveM
  */
@@ -267,27 +256,19 @@ static unsigned char snd_cs4231_original_image[32] =
 
 static u8 __cs4231_readb(struct snd_cs4231 *cp, void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
        if (cp->flags & CS4231_FLAG_EBUS)
                return readb(reg_addr);
        else
-#endif
-#ifdef SBUS_SUPPORT
                return sbus_readb(reg_addr);
-#endif
 }
 
 static void __cs4231_writeb(struct snd_cs4231 *cp, u8 val,
                            void __iomem *reg_addr)
 {
-#ifdef EBUS_SUPPORT
        if (cp->flags & CS4231_FLAG_EBUS)
                return writeb(val, reg_addr);
        else
-#endif
-#ifdef SBUS_SUPPORT
                return sbus_writeb(val, reg_addr);
-#endif
 }
 
 /*
@@ -1258,7 +1239,9 @@ static int __init snd_cs4231_pcm(struct snd_card *card)
        pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
        strcpy(pcm->name, "CS4231");
 
-       chip->p_dma.preallocate(chip, pcm);
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+                                             &chip->op->dev,
+                                             64 * 1024, 128 * 1024);
 
        chip->pcm = pcm;
 
@@ -1627,8 +1610,7 @@ static int __init cs4231_attach_finish(struct snd_card *card)
        if (err < 0)
                goto out_err;
 
-       chip->next = cs4231_list;
-       cs4231_list = chip;
+       dev_set_drvdata(&chip->op->dev, chip);
 
        dev++;
        return 0;
@@ -1783,24 +1765,19 @@ static unsigned int sbus_dma_addr(struct cs4231_dma_control *dma_cont)
        return sbus_readl(base->regs + base->dir + APCVA);
 }
 
-static void sbus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS,
-                                       snd_dma_sbus_data(chip->dev_u.sdev),
-                                       64 * 1024, 128 * 1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_sbus_free(struct snd_cs4231 *chip)
 {
+       struct of_device *op = chip->op;
+
        if (chip->irq[0])
                free_irq(chip->irq[0], chip);
 
        if (chip->port)
-               sbus_iounmap(chip->port, chip->regs_size);
+               of_iounmap(&op->resource[0], chip->port, chip->regs_size);
 
        return 0;
 }
@@ -1817,7 +1794,7 @@ static struct snd_device_ops snd_cs4231_sbus_dev_ops = {
 };
 
 static int __init snd_cs4231_sbus_create(struct snd_card *card,
-                                        struct sbus_dev *sdev,
+                                        struct of_device *op,
                                         int dev)
 {
        struct snd_cs4231 *chip = card->private_data;
@@ -1828,13 +1805,13 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        spin_lock_init(&chip->p_dma.sbus_info.lock);
        mutex_init(&chip->mce_mutex);
        mutex_init(&chip->open_mutex);
-       chip->dev_u.sdev = sdev;
-       chip->regs_size = sdev->reg_addrs[0].reg_size;
+       chip->op = op;
+       chip->regs_size = resource_size(&op->resource[0]);
        memcpy(&chip->image, &snd_cs4231_original_image,
               sizeof(snd_cs4231_original_image));
 
-       chip->port = sbus_ioremap(&sdev->resource[0], 0,
-                                 chip->regs_size, "cs4231");
+       chip->port = of_ioremap(&op->resource[0], 0,
+                               chip->regs_size, "cs4231");
        if (!chip->port) {
                snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev);
                return -EIO;
@@ -1849,22 +1826,20 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        chip->p_dma.enable = sbus_dma_enable;
        chip->p_dma.request = sbus_dma_request;
        chip->p_dma.address = sbus_dma_addr;
-       chip->p_dma.preallocate = sbus_dma_preallocate;
 
        chip->c_dma.prepare = sbus_dma_prepare;
        chip->c_dma.enable = sbus_dma_enable;
        chip->c_dma.request = sbus_dma_request;
        chip->c_dma.address = sbus_dma_addr;
-       chip->c_dma.preallocate = sbus_dma_preallocate;
 
-       if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
+       if (request_irq(op->irqs[0], snd_cs4231_sbus_interrupt,
                        IRQF_SHARED, "cs4231", chip)) {
                snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %d\n",
-                           dev, sdev->irqs[0]);
+                           dev, op->irqs[0]);
                snd_cs4231_sbus_free(chip);
                return -EBUSY;
        }
-       chip->irq[0] = sdev->irqs[0];
+       chip->irq[0] = op->irqs[0];
 
        if (snd_cs4231_probe(chip) < 0) {
                snd_cs4231_sbus_free(chip);
@@ -1881,9 +1856,9 @@ static int __init snd_cs4231_sbus_create(struct snd_card *card,
        return 0;
 }
 
-static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
+static int __devinit cs4231_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct resource *rp = &sdev->resource[0];
+       struct resource *rp = &op->resource[0];
        struct snd_card *card;
        int err;
 
@@ -1895,9 +1870,9 @@ static int __init cs4231_sbus_attach(struct sbus_dev *sdev)
                card->shortname,
                rp->flags & 0xffL,
                (unsigned long long)rp->start,
-               sdev->irqs[0]);
+               op->irqs[0]);
 
-       err = snd_cs4231_sbus_create(card, sdev, dev);
+       err = snd_cs4231_sbus_create(card, op, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -1950,30 +1925,25 @@ static unsigned int _ebus_dma_addr(struct cs4231_dma_control *dma_cont)
        return ebus_dma_addr(&dma_cont->ebus_info);
 }
 
-static void _ebus_dma_preallocate(struct snd_cs4231 *chip, struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-                                     snd_dma_pci_data(chip->dev_u.pdev),
-                                     64*1024, 128*1024);
-}
-
 /*
  * Init and exit routines
  */
 
 static int snd_cs4231_ebus_free(struct snd_cs4231 *chip)
 {
+       struct of_device *op = chip->op;
+
        if (chip->c_dma.ebus_info.regs) {
                ebus_dma_unregister(&chip->c_dma.ebus_info);
-               iounmap(chip->c_dma.ebus_info.regs);
+               of_iounmap(&op->resource[2], chip->c_dma.ebus_info.regs, 0x10);
        }
        if (chip->p_dma.ebus_info.regs) {
                ebus_dma_unregister(&chip->p_dma.ebus_info);
-               iounmap(chip->p_dma.ebus_info.regs);
+               of_iounmap(&op->resource[1], chip->p_dma.ebus_info.regs, 0x10);
        }
 
        if (chip->port)
-               iounmap(chip->port);
+               of_iounmap(&op->resource[0], chip->port, 0x10);
 
        return 0;
 }
@@ -1990,7 +1960,7 @@ static struct snd_device_ops snd_cs4231_ebus_dev_ops = {
 };
 
 static int __init snd_cs4231_ebus_create(struct snd_card *card,
-                                        struct linux_ebus_device *edev,
+                                        struct of_device *op,
                                         int dev)
 {
        struct snd_cs4231 *chip = card->private_data;
@@ -2002,35 +1972,35 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
        mutex_init(&chip->mce_mutex);
        mutex_init(&chip->open_mutex);
        chip->flags |= CS4231_FLAG_EBUS;
-       chip->dev_u.pdev = edev->bus->self;
+       chip->op = op;
        memcpy(&chip->image, &snd_cs4231_original_image,
               sizeof(snd_cs4231_original_image));
        strcpy(chip->c_dma.ebus_info.name, "cs4231(capture)");
        chip->c_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
        chip->c_dma.ebus_info.callback = snd_cs4231_ebus_capture_callback;
        chip->c_dma.ebus_info.client_cookie = chip;
-       chip->c_dma.ebus_info.irq = edev->irqs[0];
+       chip->c_dma.ebus_info.irq = op->irqs[0];
        strcpy(chip->p_dma.ebus_info.name, "cs4231(play)");
        chip->p_dma.ebus_info.flags = EBUS_DMA_FLAG_USE_EBDMA_HANDLER;
        chip->p_dma.ebus_info.callback = snd_cs4231_ebus_play_callback;
        chip->p_dma.ebus_info.client_cookie = chip;
-       chip->p_dma.ebus_info.irq = edev->irqs[1];
+       chip->p_dma.ebus_info.irq = op->irqs[1];
 
        chip->p_dma.prepare = _ebus_dma_prepare;
        chip->p_dma.enable = _ebus_dma_enable;
        chip->p_dma.request = _ebus_dma_request;
        chip->p_dma.address = _ebus_dma_addr;
-       chip->p_dma.preallocate = _ebus_dma_preallocate;
 
        chip->c_dma.prepare = _ebus_dma_prepare;
        chip->c_dma.enable = _ebus_dma_enable;
        chip->c_dma.request = _ebus_dma_request;
        chip->c_dma.address = _ebus_dma_addr;
-       chip->c_dma.preallocate = _ebus_dma_preallocate;
 
-       chip->port = ioremap(edev->resource[0].start, 0x10);
-       chip->p_dma.ebus_info.regs = ioremap(edev->resource[1].start, 0x10);
-       chip->c_dma.ebus_info.regs = ioremap(edev->resource[2].start, 0x10);
+       chip->port = of_ioremap(&op->resource[0], 0, 0x10, "cs4231");
+       chip->p_dma.ebus_info.regs =
+               of_ioremap(&op->resource[1], 0, 0x10, "cs4231_pdma");
+       chip->c_dma.ebus_info.regs =
+               of_ioremap(&op->resource[2], 0, 0x10, "cs4231_cdma");
        if (!chip->port || !chip->p_dma.ebus_info.regs ||
            !chip->c_dma.ebus_info.regs) {
                snd_cs4231_ebus_free(chip);
@@ -2078,7 +2048,7 @@ static int __init snd_cs4231_ebus_create(struct snd_card *card,
        return 0;
 }
 
-static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
+static int __devinit cs4231_ebus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct snd_card *card;
        int err;
@@ -2089,10 +2059,10 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
 
        sprintf(card->longname, "%s at 0x%lx, irq %d",
                card->shortname,
-               edev->resource[0].start,
-               edev->irqs[0]);
+               op->resource[0].start,
+               op->irqs[0]);
 
-       err = snd_cs4231_ebus_create(card, edev, dev);
+       err = snd_cs4231_ebus_create(card, op, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -2102,68 +2072,57 @@ static int __init cs4231_ebus_attach(struct linux_ebus_device *edev)
 }
 #endif
 
-static int __init cs4231_init(void)
+static int __devinit cs4231_probe(struct of_device *op, const struct of_device_id *match)
 {
-#ifdef SBUS_SUPPORT
-       struct sbus_bus *sbus;
-       struct sbus_dev *sdev;
-#endif
 #ifdef EBUS_SUPPORT
-       struct linux_ebus *ebus;
-       struct linux_ebus_device *edev;
+       if (!strcmp(op->node->parent->name, "ebus"))
+               return cs4231_ebus_probe(op, match);
 #endif
-       int found;
-
-       found = 0;
-
 #ifdef SBUS_SUPPORT
-       for_all_sbusdev(sdev, sbus) {
-               if (!strcmp(sdev->prom_name, "SUNW,CS4231")) {
-                       if (cs4231_sbus_attach(sdev) == 0)
-                               found++;
-               }
-       }
+       if (!strcmp(op->node->parent->name, "sbus") ||
+           !strcmp(op->node->parent->name, "sbi"))
+               return cs4231_sbus_probe(op, match);
 #endif
-#ifdef EBUS_SUPPORT
-       for_each_ebus(ebus) {
-               for_each_ebusdev(edev, ebus) {
-                       int match = 0;
-
-                       if (!strcmp(edev->prom_node->name, "SUNW,CS4231")) {
-                               match = 1;
-                       } else if (!strcmp(edev->prom_node->name, "audio")) {
-                               const char *compat;
-
-                               compat = of_get_property(edev->prom_node,
-                                                        "compatible", NULL);
-                               if (compat && !strcmp(compat, "SUNW,CS4231"))
-                                       match = 1;
-                       }
+       return -ENODEV;
+}
 
-                       if (match &&
-                           cs4231_ebus_attach(edev) == 0)
-                               found++;
-               }
-       }
-#endif
+static int __devexit cs4231_remove(struct of_device *op)
+{
+       struct snd_cs4231 *chip = dev_get_drvdata(&op->dev);
 
+       snd_card_free(chip->card);
 
-       return (found > 0) ? 0 : -EIO;
+       return 0;
 }
 
-static void __exit cs4231_exit(void)
-{
-       struct snd_cs4231 *p = cs4231_list;
+static const struct of_device_id cs4231_match[] = {
+       {
+               .name = "SUNW,CS4231",
+       },
+       {
+               .name = "audio",
+               .compatible = "SUNW,CS4231",
+       },
+       {},
+};
 
-       while (p != NULL) {
-               struct snd_cs4231 *next = p->next;
+MODULE_DEVICE_TABLE(of, cs4231_match);
 
-               snd_card_free(p->card);
+static struct of_platform_driver cs4231_driver = {
+       .name           = "audio",
+       .match_table    = cs4231_match,
+       .probe          = cs4231_probe,
+       .remove         = __devexit_p(cs4231_remove),
+};
 
-               p = next;
-       }
+static int __init cs4231_init(void)
+{
+       return of_register_driver(&cs4231_driver, &of_bus_type);
+}
 
-       cs4231_list = NULL;
+static void __exit cs4231_exit(void)
+{
+       of_unregister_driver(&cs4231_driver);
 }
 
 module_init(cs4231_init);
index c534a2a849fad3e1250f199ca1764b91540227b1..c257ad8bdfbcf2f02055002cad0f6ed104a7db5e 100644 (file)
@@ -57,6 +57,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -66,7 +67,7 @@
 #include <sound/initval.h>
 
 #include <linux/of.h>
-#include <asm/sbus.h>
+#include <linux/of_device.h>
 #include <asm/atomic.h>
 
 MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
@@ -297,7 +298,7 @@ struct dbri_streaminfo {
 /* This structure holds the information for both chips (DBRI & CS4215) */
 struct snd_dbri {
        int regs_size, irq;     /* Needed for unload */
-       struct sbus_dev *sdev;  /* SBUS device info */
+       struct of_device *op;   /* OF device info */
        spinlock_t lock;
 
        struct dbri_dma *dma;   /* Pointer to our DMA block */
@@ -2093,14 +2094,15 @@ static int snd_dbri_hw_params(struct snd_pcm_substream *substream,
         */
        if (info->dvma_buffer == 0) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               info->dvma_buffer = sbus_map_single(dbri->sdev,
-                                       runtime->dma_area,
-                                       params_buffer_bytes(hw_params),
-                                       direction);
+               info->dvma_buffer =
+                       dma_map_single(&dbri->op->dev,
+                                      runtime->dma_area,
+                                      params_buffer_bytes(hw_params),
+                                      direction);
        }
 
        direction = params_buffer_bytes(hw_params);
@@ -2121,12 +2123,12 @@ static int snd_dbri_hw_free(struct snd_pcm_substream *substream)
         */
        if (info->dvma_buffer) {
                if (DBRI_STREAMNO(substream) == DBRI_PLAY)
-                       direction = SBUS_DMA_TODEVICE;
+                       direction = DMA_TO_DEVICE;
                else
-                       direction = SBUS_DMA_FROMDEVICE;
+                       direction = DMA_FROM_DEVICE;
 
-               sbus_unmap_single(dbri->sdev, info->dvma_buffer,
-                                 substream->runtime->buffer_size, direction);
+               dma_unmap_single(&dbri->op->dev, info->dvma_buffer,
+                                substream->runtime->buffer_size, direction);
                info->dvma_buffer = 0;
        }
        if (info->pipe != -1) {
@@ -2519,31 +2521,32 @@ static void __devinit snd_dbri_proc(struct snd_card *card)
 static void snd_dbri_free(struct snd_dbri *dbri);
 
 static int __devinit snd_dbri_create(struct snd_card *card,
-                                 struct sbus_dev *sdev,
-                                 int irq, int dev)
+                                    struct of_device *op,
+                                    int irq, int dev)
 {
        struct snd_dbri *dbri = card->private_data;
        int err;
 
        spin_lock_init(&dbri->lock);
-       dbri->sdev = sdev;
+       dbri->op = op;
        dbri->irq = irq;
 
-       dbri->dma = sbus_alloc_consistent(sdev, sizeof(struct dbri_dma),
-                                         &dbri->dma_dvma);
+       dbri->dma = dma_alloc_coherent(&op->dev,
+                                      sizeof(struct dbri_dma),
+                                      &dbri->dma_dvma, GFP_ATOMIC);
        memset((void *)dbri->dma, 0, sizeof(struct dbri_dma));
 
        dprintk(D_GEN, "DMA Cmd Block 0x%p (0x%08x)\n",
                dbri->dma, dbri->dma_dvma);
 
        /* Map the registers into memory. */
-       dbri->regs_size = sdev->reg_addrs[0].reg_size;
-       dbri->regs = sbus_ioremap(&sdev->resource[0], 0,
-                                 dbri->regs_size, "DBRI Registers");
+       dbri->regs_size = resource_size(&op->resource[0]);
+       dbri->regs = of_ioremap(&op->resource[0], 0,
+                               dbri->regs_size, "DBRI Registers");
        if (!dbri->regs) {
                printk(KERN_ERR "DBRI: could not allocate registers\n");
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return -EIO;
        }
 
@@ -2551,9 +2554,9 @@ static int __devinit snd_dbri_create(struct snd_card *card,
                          "DBRI audio", dbri);
        if (err) {
                printk(KERN_ERR "DBRI: Can't get irq %d\n", dbri->irq);
-               sbus_iounmap(dbri->regs, dbri->regs_size);
-               sbus_free_consistent(sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               of_iounmap(&op->resource[0], dbri->regs, dbri->regs_size);
+               dma_free_coherent(&op->dev, sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
                return err;
        }
 
@@ -2577,27 +2580,23 @@ static void snd_dbri_free(struct snd_dbri *dbri)
                free_irq(dbri->irq, dbri);
 
        if (dbri->regs)
-               sbus_iounmap(dbri->regs, dbri->regs_size);
+               of_iounmap(&dbri->op->resource[0], dbri->regs, dbri->regs_size);
 
        if (dbri->dma)
-               sbus_free_consistent(dbri->sdev, sizeof(struct dbri_dma),
-                                    (void *)dbri->dma, dbri->dma_dvma);
+               dma_free_coherent(&dbri->op->dev,
+                                 sizeof(struct dbri_dma),
+                                 (void *)dbri->dma, dbri->dma_dvma);
 }
 
-static int __devinit dbri_probe(struct of_device *of_dev,
-                               const struct of_device_id *match)
+static int __devinit dbri_probe(struct of_device *op, const struct of_device_id *match)
 {
-       struct sbus_dev *sdev = to_sbus_device(&of_dev->dev);
        struct snd_dbri *dbri;
-       int irq;
        struct resource *rp;
        struct snd_card *card;
        static int dev = 0;
+       int irq;
        int err;
 
-       dprintk(D_GEN, "DBRI: Found %s in SBUS slot %d\n",
-               sdev->prom_name, sdev->slot);
-
        if (dev >= SNDRV_CARDS)
                return -ENODEV;
        if (!enable[dev]) {
@@ -2605,7 +2604,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
                return -ENOENT;
        }
 
-       irq = sdev->irqs[0];
+       irq = op->irqs[0];
        if (irq <= 0) {
                printk(KERN_ERR "DBRI-%d: No IRQ.\n", dev);
                return -ENODEV;
@@ -2618,12 +2617,12 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        strcpy(card->driver, "DBRI");
        strcpy(card->shortname, "Sun DBRI");
-       rp = &sdev->resource[0];
+       rp = &op->resource[0];
        sprintf(card->longname, "%s at 0x%02lx:0x%016Lx, irq %d",
                card->shortname,
                rp->flags & 0xffL, (unsigned long long)rp->start, irq);
 
-       err = snd_dbri_create(card, sdev, irq, dev);
+       err = snd_dbri_create(card, op, irq, dev);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -2640,7 +2639,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        /* /proc file handling */
        snd_dbri_proc(card);
-       dev_set_drvdata(&of_dev->dev, card);
+       dev_set_drvdata(&op->dev, card);
 
        err = snd_card_register(card);
        if (err < 0)
@@ -2648,7 +2647,7 @@ static int __devinit dbri_probe(struct of_device *of_dev,
 
        printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n",
               dev, dbri->regs,
-              dbri->irq, sdev->prom_name[9], dbri->mm.version);
+              dbri->irq, op->node->name[9], dbri->mm.version);
        dev++;
 
        return 0;
@@ -2659,19 +2658,19 @@ _err:
        return err;
 }
 
-static int __devexit dbri_remove(struct of_device *dev)
+static int __devexit dbri_remove(struct of_device *op)
 {
-       struct snd_card *card = dev_get_drvdata(&dev->dev);
+       struct snd_card *card = dev_get_drvdata(&op->dev);
 
        snd_dbri_free(card->private_data);
        snd_card_free(card);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-static struct of_device_id dbri_match[] = {
+static const struct of_device_id dbri_match[] = {
        {
                .name = "SUNW,DBRIe",
        },
@@ -2693,7 +2692,7 @@ static struct of_platform_driver dbri_sbus_driver = {
 /* Probe for the dbri chip and then attach the driver. */
 static int __init dbri_init(void)
 {
-       return of_register_driver(&dbri_sbus_driver, &sbus_bus_type);
+       return of_register_driver(&dbri_sbus_driver, &of_bus_type);
 }
 
 static void __exit dbri_exit(void)